Commit 806f78fc authored by Kushal Pandya's avatar Kushal Pandya

Weeks Preset Mixin

parent 8f046d62
import { TIMELINE_END_OFFSET_HALF } from '../constants';
export default {
methods: {
/**
* Check if current epic starts within current week (timeline cell)
*/
hasStartDateForWeek() {
const firstDayOfWeek = this.timeframeItem;
const lastDayOfWeek = new Date(this.timeframeItem.getTime());
lastDayOfWeek.setDate(lastDayOfWeek.getDate() + 6);
return this.epic.startDate >= firstDayOfWeek && this.epic.startDate <= lastDayOfWeek;
},
/**
* Return last date of the week from provided timeframeItem
*/
getLastDayOfWeek(timeframeItem) {
const lastDayOfWeek = new Date(timeframeItem.getTime());
lastDayOfWeek.setDate(lastDayOfWeek.getDate() + 6);
return lastDayOfWeek;
},
/**
* Check if current epic ends within current week (timeline cell)
*/
isTimeframeUnderEndDateForWeek(timeframeItem, epicEndDate) {
const lastDayOfWeek = this.getLastDayOfWeek(timeframeItem);
return epicEndDate <= lastDayOfWeek;
},
/**
* Return timeline bar width for current week (timeline cell) based on
* cellWidth, days in week (7) and day of the week (non-zero based index)
*/
getBarWidthForSingleWeek(cellWidth, day) {
const dayWidth = cellWidth / 7;
const barWidth = day === 7 ? cellWidth : dayWidth * day;
return Math.min(cellWidth, barWidth);
},
/**
* Gets timelinebar end offset based width of single day
* and TIMELINE_END_OFFSET_HALF
*/
getTimelineBarEndOffsetHalfForWeek() {
const dayWidth = this.getCellWidth() / 7;
return TIMELINE_END_OFFSET_HALF + (dayWidth * 0.5);
},
/**
* In case startDate for any epic is undefined or is out of range
* for current timeframe, we have to provide specific offset while
* positioning it to ensure that;
*
* 1. Timeline bar starts at correct position based on start date.
* 2. Bar starts exactly at the start of cell in case start date is `1`.
* 3. A "triangle" shape is shown at the beginning of timeline bar
* when startDate is out of range.
*
* Implementation of this method is identical to
* MonthsPresetMixin#getTimelineBarStartOffsetForMonths
*/
getTimelineBarStartOffsetForWeeks() {
const daysInWeek = 7;
const dayWidth = this.getCellWidth() / daysInWeek;
const startDate = this.epic.startDate.getDay() + 1;
const firstDayOfWeek = this.timeframeItem.getDay() + 1;
if (
this.epic.startDateOutOfRange ||
(this.epic.startDateUndefined && this.epic.endDateOutOfRange)
) {
return '';
} else if (startDate === firstDayOfWeek) {
return 'left: 0;';
}
const lastTimeframeItem = new Date(this.timeframe[this.timeframe.length - 1].getTime());
lastTimeframeItem.setDate(lastTimeframeItem.getDate() + 6);
if (
this.epic.startDate >= this.timeframe[this.timeframe.length - 1] &&
this.epic.startDate <= lastTimeframeItem
) {
return `right: ${TIMELINE_END_OFFSET_HALF}px;`;
}
return `left: ${(startDate * dayWidth) - (dayWidth / 2)}px;`;
},
/**
* This method is externally only called when current timeframe cell has timeline
* bar to show. So when this method is called, we iterate over entire timeframe
* array starting from current timeframeItem.
*
* For eg;
* If timeframe range for 6 weeks is;
* May 27, Jun 3, Jun 10, Jun 17, Jun 24, Jul 1
*
* And if Epic starts in May 30 and ends on June 20.
*
* Then this method will iterate over timeframe as;
* May 27 => Jun 17
* And will add up width(see 1.) for timeline bar for each week in iteration
* based on provided start and end dates.
*
* 1. Width from date is calculated by totalWidthCell / totalDaysInWeek = widthOfSingleDay
* and then dayOfWeek x widthOfSingleDay = totalBarWidth
*
* Implementation of this method is identical to
* MonthsPresetMixin#getTimelineBarWidthForMonths
*/
getTimelineBarWidthForWeeks() {
let timelineBarWidth = 0;
const indexOfCurrentWeek = this.timeframe.indexOf(this.timeframeItem);
const cellWidth = this.getCellWidth();
const offsetEnd = this.getTimelineBarEndOffset();
const epicStartDate = this.epic.startDate;
const epicEndDate = this.epic.endDate;
for (let i = indexOfCurrentWeek; i < this.timeframe.length; i += 1) {
if (i === indexOfCurrentWeek) {
if (this.isTimeframeUnderEndDateForWeek(this.timeframe[i], epicEndDate)) {
timelineBarWidth += this.getBarWidthForSingleWeek(
cellWidth,
epicEndDate.getDay() - epicStartDate.getDay() + 1,
);
break;
} else {
const date = epicStartDate.getDay() === 0 ? 7 : 7 - epicStartDate.getDay();
timelineBarWidth += this.getBarWidthForSingleWeek(cellWidth, date);
}
} else if (this.isTimeframeUnderEndDateForWeek(this.timeframe[i], epicEndDate)) {
timelineBarWidth += this.getBarWidthForSingleWeek(cellWidth, epicEndDate.getDay() + 1);
break;
} else {
timelineBarWidth += this.getBarWidthForSingleWeek(cellWidth, 7);
}
}
return timelineBarWidth - offsetEnd;
},
},
};
import Vue from 'vue';
import EpicItemTimelineComponent from 'ee/roadmap/components/epic_item_timeline.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockTimeframeWeeks, mockEpic, mockShellWidth, mockItemWidth } from '../mock_data';
const createComponent = ({
presetType = PRESET_TYPES.WEEKS,
timeframe = mockTimeframeWeeks,
timeframeItem = mockTimeframeWeeks[0],
epic = mockEpic,
shellWidth = mockShellWidth,
itemWidth = mockItemWidth,
}) => {
const Component = Vue.extend(EpicItemTimelineComponent);
return mountComponent(Component, {
presetType,
timeframe,
timeframeItem,
epic,
shellWidth,
itemWidth,
});
};
describe('WeeksPresetMixin', () => {
let vm;
afterEach(() => {
vm.$destroy();
});
describe('methods', () => {
describe('hasStartDateForWeek', () => {
it('returns true when Epic.startDate falls within timeframeItem', () => {
vm = createComponent({
epic: Object.assign({}, mockEpic, { startDate: mockTimeframeWeeks[1] }),
timeframeItem: mockTimeframeWeeks[1],
});
expect(vm.hasStartDateForWeek()).toBe(true);
});
it('returns false when Epic.startDate does not fall within timeframeItem', () => {
vm = createComponent({
epic: Object.assign({}, mockEpic, { startDate: mockTimeframeWeeks[0] }),
timeframeItem: mockTimeframeWeeks[1],
});
expect(vm.hasStartDateForWeek()).toBe(false);
});
});
describe('getLastDayOfWeek', () => {
it('returns date object set to last day of the week from provided timeframeItem', () => {
vm = createComponent({});
const lastDayOfWeek = vm.getLastDayOfWeek(mockTimeframeWeeks[0]);
expect(lastDayOfWeek.getDate()).toBe(30);
expect(lastDayOfWeek.getMonth()).toBe(11);
expect(lastDayOfWeek.getFullYear()).toBe(2017);
});
});
describe('isTimeframeUnderEndDateForWeek', () => {
beforeEach(() => {
vm = createComponent({});
});
it('returns true if provided timeframeItem is under epicEndDate', () => {
const timeframeItem = new Date(2018, 0, 7); // Jan 7, 2018
const epicEndDate = new Date(2018, 0, 3); // Jan 3, 2018
expect(vm.isTimeframeUnderEndDateForWeek(timeframeItem, epicEndDate)).toBe(true);
});
it('returns false if provided timeframeItem is NOT under epicEndDate', () => {
const timeframeItem = new Date(2018, 0, 7); // Jan 7, 2018
const epicEndDate = new Date(2018, 0, 15); // Jan 15, 2018
expect(vm.isTimeframeUnderEndDateForWeek(timeframeItem, epicEndDate)).toBe(false);
});
});
describe('getBarWidthForSingleWeek', () => {
it('returns calculated bar width based on provided cellWidth and day of week', () => {
vm = createComponent({});
expect(Math.floor(vm.getBarWidthForSingleWeek(300, 1))).toBe(42); // 10% size
expect(Math.floor(vm.getBarWidthForSingleWeek(300, 3))).toBe(128); // 50% size
expect(vm.getBarWidthForSingleWeek(300, 7)).toBe(300); // Full size
});
});
describe('getTimelineBarEndOffsetHalfForWeek', () => {
it('returns timeline bar end offset for Weeks view', () => {
vm = createComponent({});
expect(vm.getTimelineBarEndOffsetHalfForWeek()).toBe(28);
});
});
describe('getTimelineBarStartOffsetForWeeks', () => {
it('returns empty string when Epic startDate is out of range', () => {
vm = createComponent({
epic: Object.assign({}, mockEpic, { startDateOutOfRange: true }),
});
expect(vm.getTimelineBarStartOffsetForWeeks()).toBe('');
});
it('returns empty string when Epic startDate is undefined and endDate is out of range', () => {
vm = createComponent({
epic: Object.assign({}, mockEpic, {
startDateUndefined: true,
endDateOutOfRange: true,
}),
});
expect(vm.getTimelineBarStartOffsetForWeeks()).toBe('');
});
it('return `left: 0;` when Epic startDate is first day of the week', () => {
vm = createComponent({
epic: Object.assign({}, mockEpic, {
startDate: mockTimeframeWeeks[0],
}),
});
expect(vm.getTimelineBarStartOffsetForWeeks()).toBe('left: 0;');
});
it('returns `right: 8px;` when Epic startDate is in last timeframe month and endDate is out of range', () => {
const startDate = new Date(mockTimeframeWeeks[mockTimeframeWeeks.length - 1].getTime());
startDate.setDate(startDate.getDate() + 1);
vm = createComponent({
epic: Object.assign({}, mockEpic, {
startDate,
endDateOutOfRange: true,
}),
});
expect(vm.getTimelineBarStartOffsetForWeeks()).toBe('right: 8px;');
});
it('returns proportional `left` value based on Epic startDate and days in the month', () => {
vm = createComponent({
epic: Object.assign({}, mockEpic, {
startDate: new Date(2018, 0, 15),
}),
});
expect(vm.getTimelineBarStartOffsetForWeeks()).toContain('left: 60');
});
});
describe('getTimelineBarWidthForWeeks', () => {
it('returns calculated width value based on Epic.startDate and Epic.endDate', () => {
vm = createComponent({
shellWidth: 2000,
timeframeItem: mockTimeframeWeeks[0],
epic: Object.assign({}, mockEpic, {
startDate: new Date(2018, 0, 1), // Jan 1, 2018
endDate: new Date(2018, 1, 2), // Feb 2, 2018
}),
});
expect(Math.floor(vm.getTimelineBarWidthForWeeks())).toBe(1600);
});
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment