Sort groups and items correctly
fixes ADMIN-994 test plan: - fill one day of a planner with stuff. Put items in multiple courses, with multiple due dates and times. Include some user todos not in a course. > expect the groupings and items to be ordered: - Groupings are alpha by course/group name - Except that To Dos are last - Within each grouping, - items are ordered by due time, first things first - then alpha by item title if matching due times Change-Id: Idcac554b93f908e5643db87fc913c69238e2cb15 Reviewed-on: https://gerrit.instructure.com/149416 Tested-by: Jenkins Reviewed-by: Jon Willesen <jonw+gerrit@instructure.com> QA-Review: Deepeeca Soundarrajan <dsoundarrajan@instructure.com> Product-Review: Christi Wruck
This commit is contained in:
parent
5441e760e9
commit
bf25c7b988
|
@ -44,49 +44,11 @@ it('renders the friendlyName in medium text when it is not today', () => {
|
|||
expect(wrapper.find('Text').first().props().size).toEqual('medium');
|
||||
});
|
||||
|
||||
it('groups itemsForDay based on context type + context id', () => {
|
||||
const items = [{
|
||||
title: 'Black Friday',
|
||||
context: {
|
||||
type: 'Course',
|
||||
id: 128,
|
||||
inform_students_of_overdue_submissions: true
|
||||
}
|
||||
}, {
|
||||
title: 'San Juan',
|
||||
context: {
|
||||
type: 'Course',
|
||||
id: 256,
|
||||
inform_students_of_overdue_submissions: true
|
||||
}
|
||||
}, {
|
||||
title: 'Roll for the Galaxy',
|
||||
context: {
|
||||
type: 'Course',
|
||||
id: 256,
|
||||
inform_students_of_overdue_submissions: true
|
||||
}
|
||||
}, {
|
||||
title: 'Same id, different type',
|
||||
context: {
|
||||
type: 'Group',
|
||||
id: 256,
|
||||
inform_students_of_overdue_submissions: false
|
||||
}
|
||||
}];
|
||||
|
||||
const wrapper = shallow(
|
||||
<Day timeZone="America/Denver" day="2017-04-25" itemsForDay={items} />
|
||||
);
|
||||
const groupedItems = wrapper.state('groupedItems');
|
||||
expect(groupedItems['Course128'].length).toEqual(1);
|
||||
expect(groupedItems['Course256'].length).toEqual(2);
|
||||
expect(groupedItems['Group256'].length).toEqual(1);
|
||||
});
|
||||
|
||||
it('renders grouping correctly when having itemsForDay', () => {
|
||||
const TZ = "America/Denver";
|
||||
const items = [{
|
||||
title: 'Black Friday',
|
||||
date: moment.tz('2017-04-25T23:59:00Z', TZ),
|
||||
context: {
|
||||
type: 'Course',
|
||||
id: 128,
|
||||
|
@ -95,6 +57,7 @@ it('renders grouping correctly when having itemsForDay', () => {
|
|||
}
|
||||
}, {
|
||||
title: 'San Juan',
|
||||
date: moment.tz('2017-04-25T23:59:00Z', TZ),
|
||||
context: {
|
||||
type: 'Course',
|
||||
id: 256,
|
||||
|
@ -103,6 +66,7 @@ it('renders grouping correctly when having itemsForDay', () => {
|
|||
}
|
||||
}, {
|
||||
title: 'Roll for the Galaxy',
|
||||
date: moment.tz('2017-04-25T23:59:00Z', TZ),
|
||||
context: {
|
||||
type: 'Course',
|
||||
id: 256,
|
||||
|
@ -111,6 +75,7 @@ it('renders grouping correctly when having itemsForDay', () => {
|
|||
}
|
||||
}, {
|
||||
title: 'Same id, different type',
|
||||
date: moment.tz('2017-04-25T23:59:00Z', TZ),
|
||||
context: {
|
||||
type: 'Group',
|
||||
id: 256,
|
||||
|
@ -119,13 +84,15 @@ it('renders grouping correctly when having itemsForDay', () => {
|
|||
}];
|
||||
|
||||
const wrapper = shallow(
|
||||
<Day timeZone="America/Denver" day="2017-04-25" itemsForDay={items} animatableIndex={1}/>
|
||||
<Day timeZone={TZ} day="2017-04-25" itemsForDay={items} animatableIndex={1}/>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
it('groups itemsForDay that have no context into the "Notes" category', () => {
|
||||
const TZ = "America/Denver";
|
||||
const items = [{
|
||||
title: 'Black Friday',
|
||||
date: moment.tz('2017-04-25T23:59:00Z', TZ),
|
||||
context: {
|
||||
type: 'Course',
|
||||
id: 128,
|
||||
|
@ -133,6 +100,7 @@ it('groups itemsForDay that have no context into the "Notes" category', () => {
|
|||
}
|
||||
}, {
|
||||
title: 'San Juan',
|
||||
date: moment.tz('2017-04-25T23:59:00Z', TZ),
|
||||
context: {
|
||||
type: 'Course',
|
||||
id: 256,
|
||||
|
@ -140,6 +108,7 @@ it('groups itemsForDay that have no context into the "Notes" category', () => {
|
|||
}
|
||||
}, {
|
||||
title: 'Roll for the Galaxy',
|
||||
date: moment.tz('2017-04-25T23:59:00Z', TZ),
|
||||
context: {
|
||||
type: 'Course',
|
||||
id: 256,
|
||||
|
@ -150,15 +119,16 @@ it('groups itemsForDay that have no context into the "Notes" category', () => {
|
|||
}];
|
||||
|
||||
const wrapper = shallow(
|
||||
<Day timeZone="America/Denver" day="2017-04-25" itemsForDay={items} />
|
||||
<Day timeZone={TZ} day="2017-04-25" itemsForDay={items} />
|
||||
);
|
||||
const groupedItems = wrapper.state('groupedItems');
|
||||
expect(groupedItems.Notes.length).toEqual(1);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('groups itemsForDay that come in on prop changes', () => {
|
||||
const TZ = "America/Denver";
|
||||
const items = [{
|
||||
title: 'Black Friday',
|
||||
date: moment.tz('2017-04-25T23:59:00Z', TZ),
|
||||
context: {
|
||||
type: 'Course',
|
||||
id: 128,
|
||||
|
@ -166,6 +136,7 @@ it('groups itemsForDay that come in on prop changes', () => {
|
|||
}
|
||||
}, {
|
||||
title: 'San Juan',
|
||||
date: moment.tz('2017-04-25T23:59:00Z', TZ),
|
||||
context: {
|
||||
type: 'Course',
|
||||
id: 256,
|
||||
|
@ -174,13 +145,13 @@ it('groups itemsForDay that come in on prop changes', () => {
|
|||
}];
|
||||
|
||||
const wrapper = shallow(
|
||||
<Day timeZone="America/Denver" day="2017-04-25" itemsForDay={items} registerAnimatable={() => {}} deregisterAnimatable={() => {}} />
|
||||
<Day timeZone={TZ} day="2017-04-25" itemsForDay={items} registerAnimatable={() => {}} deregisterAnimatable={() => {}} />
|
||||
);
|
||||
let groupedItems = wrapper.state('groupedItems');
|
||||
expect(Object.keys(groupedItems).length).toEqual(2);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
||||
const newItemsForDay = items.concat([{
|
||||
title: 'Roll for the Galaxy',
|
||||
date: moment.tz('2017-04-25T23:59:00Z', TZ),
|
||||
context: {
|
||||
type: 'Course',
|
||||
id: 256,
|
||||
|
@ -191,8 +162,7 @@ it('groups itemsForDay that come in on prop changes', () => {
|
|||
}]);
|
||||
|
||||
wrapper.setProps({ itemsForDay: newItemsForDay });
|
||||
groupedItems = wrapper.state('groupedItems');
|
||||
expect(Object.keys(groupedItems).length).toEqual(3);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
||||
|
@ -205,14 +175,21 @@ it('renders even when there are no items', () => {
|
|||
});
|
||||
|
||||
it('registers itself as animatable', () => {
|
||||
const TZ = "Asia/Tokyo";
|
||||
const fakeRegister = jest.fn();
|
||||
const fakeDeregister = jest.fn();
|
||||
const firstItems = [{title: 'asdf', context: {id: 128, inform_students_of_overdue_submissions: true}, id: '1', uniqueId: 'first'}, {title: 'jkl', context: {id: 256, inform_students_of_overdue_submissions: true}, id: '2', uniqueId: 'second'}];
|
||||
const secondItems = [{title: 'qwer', context: {id: 128, inform_students_of_overdue_submissions: true}, id: '3', uniqueId: 'third'}, {title: 'uiop', context: {id: 256, inform_students_of_overdue_submissions: true}, id: '4', uniqueId: 'fourth'}];
|
||||
const firstItems = [
|
||||
{title: 'asdf', date: moment.tz('2017-04-25T23:59:00Z', TZ), context: {id: 128, inform_students_of_overdue_submissions: true}, id: '1', uniqueId: 'first'},
|
||||
{title: 'jkl', date: moment.tz('2017-04-25T23:59:00Z', TZ), context: {id: 256, inform_students_of_overdue_submissions: true}, id: '2', uniqueId: 'second'}
|
||||
];
|
||||
const secondItems = [
|
||||
{title: 'qwer', date: moment.tz('2017-04-25T23:59:00Z', TZ), context: {id: 128, inform_students_of_overdue_submissions: true}, id: '3', uniqueId: 'third'},
|
||||
{title: 'uiop', date: moment.tz('2017-04-25T23:59:00Z', TZ), context: {id: 256, inform_students_of_overdue_submissions: true}, id: '4', uniqueId: 'fourth'}
|
||||
];
|
||||
const wrapper = mount(
|
||||
<Day
|
||||
day={'2017-08-11'}
|
||||
timeZone="Asia/Tokyo"
|
||||
timeZone={TZ}
|
||||
animatableIndex={42}
|
||||
itemsForDay={firstItems}
|
||||
registerAnimatable={fakeRegister}
|
||||
|
|
|
@ -1,5 +1,286 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`groups itemsForDay that come in on prop changes 1`] = `
|
||||
<div
|
||||
className="planner-day"
|
||||
>
|
||||
<Heading
|
||||
border="none"
|
||||
color="inherit"
|
||||
ellipsis={false}
|
||||
level="h2"
|
||||
>
|
||||
<Text
|
||||
as="div"
|
||||
letterSpacing="normal"
|
||||
lineHeight="condensed"
|
||||
size="medium"
|
||||
transform="uppercase"
|
||||
>
|
||||
Tuesday
|
||||
</Text>
|
||||
<Text
|
||||
as="div"
|
||||
letterSpacing="normal"
|
||||
lineHeight="condensed"
|
||||
size="medium"
|
||||
>
|
||||
April 25, 2017
|
||||
</Text>
|
||||
</Heading>
|
||||
<div>
|
||||
<Animatable(ResponsiveGrouping)
|
||||
animatableIndex={1}
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
"context": Object {
|
||||
"id": 128,
|
||||
"inform_students_of_overdue_submissions": true,
|
||||
"type": "Course",
|
||||
},
|
||||
"date": "2017-04-25T23:59:00.000Z",
|
||||
"title": "Black Friday",
|
||||
},
|
||||
]
|
||||
}
|
||||
theme={
|
||||
Object {
|
||||
"titleColor": null,
|
||||
}
|
||||
}
|
||||
timeZone="America/Denver"
|
||||
/>
|
||||
<Animatable(ResponsiveGrouping)
|
||||
animatableIndex={2}
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
"context": Object {
|
||||
"id": 256,
|
||||
"inform_students_of_overdue_submissions": true,
|
||||
"type": "Course",
|
||||
},
|
||||
"date": "2017-04-25T23:59:00.000Z",
|
||||
"title": "San Juan",
|
||||
},
|
||||
]
|
||||
}
|
||||
theme={
|
||||
Object {
|
||||
"titleColor": null,
|
||||
}
|
||||
}
|
||||
timeZone="America/Denver"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`groups itemsForDay that come in on prop changes 2`] = `
|
||||
<div
|
||||
className="planner-day"
|
||||
>
|
||||
<Heading
|
||||
border="none"
|
||||
color="inherit"
|
||||
ellipsis={false}
|
||||
level="h2"
|
||||
>
|
||||
<Text
|
||||
as="div"
|
||||
letterSpacing="normal"
|
||||
lineHeight="condensed"
|
||||
size="medium"
|
||||
transform="uppercase"
|
||||
>
|
||||
Tuesday
|
||||
</Text>
|
||||
<Text
|
||||
as="div"
|
||||
letterSpacing="normal"
|
||||
lineHeight="condensed"
|
||||
size="medium"
|
||||
>
|
||||
April 25, 2017
|
||||
</Text>
|
||||
</Heading>
|
||||
<div>
|
||||
<Animatable(ResponsiveGrouping)
|
||||
animatableIndex={1}
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
"context": Object {
|
||||
"id": 128,
|
||||
"inform_students_of_overdue_submissions": true,
|
||||
"type": "Course",
|
||||
},
|
||||
"date": "2017-04-25T23:59:00.000Z",
|
||||
"title": "Black Friday",
|
||||
},
|
||||
]
|
||||
}
|
||||
theme={
|
||||
Object {
|
||||
"titleColor": null,
|
||||
}
|
||||
}
|
||||
timeZone="America/Denver"
|
||||
/>
|
||||
<Animatable(ResponsiveGrouping)
|
||||
animatableIndex={2}
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
"context": Object {
|
||||
"id": 256,
|
||||
"inform_students_of_overdue_submissions": true,
|
||||
"type": "Course",
|
||||
},
|
||||
"date": "2017-04-25T23:59:00.000Z",
|
||||
"title": "San Juan",
|
||||
},
|
||||
Object {
|
||||
"context": Object {
|
||||
"id": 256,
|
||||
"inform_students_of_overdue_submissions": true,
|
||||
"type": "Course",
|
||||
},
|
||||
"date": "2017-04-25T23:59:00.000Z",
|
||||
"title": "Roll for the Galaxy",
|
||||
},
|
||||
]
|
||||
}
|
||||
theme={
|
||||
Object {
|
||||
"titleColor": null,
|
||||
}
|
||||
}
|
||||
timeZone="America/Denver"
|
||||
/>
|
||||
<Animatable(ResponsiveGrouping)
|
||||
animatableIndex={3}
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
"title": "Get work done!",
|
||||
},
|
||||
]
|
||||
}
|
||||
theme={
|
||||
Object {
|
||||
"titleColor": null,
|
||||
}
|
||||
}
|
||||
timeZone="America/Denver"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`groups itemsForDay that have no context into the "Notes" category 1`] = `
|
||||
<div
|
||||
className="planner-day"
|
||||
>
|
||||
<Heading
|
||||
border="none"
|
||||
color="inherit"
|
||||
ellipsis={false}
|
||||
level="h2"
|
||||
>
|
||||
<Text
|
||||
as="div"
|
||||
letterSpacing="normal"
|
||||
lineHeight="condensed"
|
||||
size="medium"
|
||||
transform="uppercase"
|
||||
>
|
||||
Tuesday
|
||||
</Text>
|
||||
<Text
|
||||
as="div"
|
||||
letterSpacing="normal"
|
||||
lineHeight="condensed"
|
||||
size="medium"
|
||||
>
|
||||
April 25, 2017
|
||||
</Text>
|
||||
</Heading>
|
||||
<div>
|
||||
<Animatable(ResponsiveGrouping)
|
||||
animatableIndex={1}
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
"context": Object {
|
||||
"id": 128,
|
||||
"inform_students_of_overdue_submissions": true,
|
||||
"type": "Course",
|
||||
},
|
||||
"date": "2017-04-25T23:59:00.000Z",
|
||||
"title": "Black Friday",
|
||||
},
|
||||
]
|
||||
}
|
||||
theme={
|
||||
Object {
|
||||
"titleColor": null,
|
||||
}
|
||||
}
|
||||
timeZone="America/Denver"
|
||||
/>
|
||||
<Animatable(ResponsiveGrouping)
|
||||
animatableIndex={2}
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
"context": Object {
|
||||
"id": 256,
|
||||
"inform_students_of_overdue_submissions": true,
|
||||
"type": "Course",
|
||||
},
|
||||
"date": "2017-04-25T23:59:00.000Z",
|
||||
"title": "San Juan",
|
||||
},
|
||||
Object {
|
||||
"context": Object {
|
||||
"id": 256,
|
||||
"inform_students_of_overdue_submissions": true,
|
||||
"type": "Course",
|
||||
},
|
||||
"date": "2017-04-25T23:59:00.000Z",
|
||||
"title": "Roll for the Galaxy",
|
||||
},
|
||||
]
|
||||
}
|
||||
theme={
|
||||
Object {
|
||||
"titleColor": null,
|
||||
}
|
||||
}
|
||||
timeZone="America/Denver"
|
||||
/>
|
||||
<Animatable(ResponsiveGrouping)
|
||||
animatableIndex={3}
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
"title": "Get work done!",
|
||||
},
|
||||
]
|
||||
}
|
||||
theme={
|
||||
Object {
|
||||
"titleColor": null,
|
||||
}
|
||||
}
|
||||
timeZone="America/Denver"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders grouping correctly when having itemsForDay 1`] = `
|
||||
<div
|
||||
className="planner-day"
|
||||
|
@ -40,6 +321,7 @@ exports[`renders grouping correctly when having itemsForDay 1`] = `
|
|||
"type": "Course",
|
||||
"url": "http://www.non_default_url.com",
|
||||
},
|
||||
"date": "2017-04-25T23:59:00.000Z",
|
||||
"title": "Black Friday",
|
||||
},
|
||||
]
|
||||
|
@ -63,6 +345,7 @@ exports[`renders grouping correctly when having itemsForDay 1`] = `
|
|||
"type": "Course",
|
||||
"url": "http://www.non_default_url.com",
|
||||
},
|
||||
"date": "2017-04-25T23:59:00.000Z",
|
||||
"title": "San Juan",
|
||||
},
|
||||
Object {
|
||||
|
@ -72,6 +355,7 @@ exports[`renders grouping correctly when having itemsForDay 1`] = `
|
|||
"type": "Course",
|
||||
"url": "http://www.non_default_url.com",
|
||||
},
|
||||
"date": "2017-04-25T23:59:00.000Z",
|
||||
"title": "Roll for the Galaxy",
|
||||
},
|
||||
]
|
||||
|
@ -94,6 +378,7 @@ exports[`renders grouping correctly when having itemsForDay 1`] = `
|
|||
"inform_students_of_overdue_submissions": false,
|
||||
"type": "Group",
|
||||
},
|
||||
"date": "2017-04-25T23:59:00.000Z",
|
||||
"title": "Same id, different type",
|
||||
},
|
||||
]
|
||||
|
|
|
@ -28,7 +28,6 @@ import { userShape, itemShape } from '../plannerPropTypes';
|
|||
import styles from './styles.css';
|
||||
import theme from './theme.js';
|
||||
import { getFriendlyDate, getFullDate, isToday } from '../../utilities/dateUtils';
|
||||
import { groupBy } from 'lodash';
|
||||
import Grouping from '../Grouping';
|
||||
import formatMessage from '../../format-message';
|
||||
import { animatable } from '../../dynamic-ui';
|
||||
|
@ -45,6 +44,9 @@ export class Day extends Component {
|
|||
deregisterAnimatable: func,
|
||||
currentUser: shape(userShape),
|
||||
};
|
||||
static defaultProps = {
|
||||
animatableIndex: 0,
|
||||
};
|
||||
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
@ -52,9 +54,6 @@ export class Day extends Component {
|
|||
const tzMomentizedDate = moment.tz(props.day, props.timeZone);
|
||||
this.friendlyName = getFriendlyDate(tzMomentizedDate);
|
||||
this.fullDate = getFullDate(tzMomentizedDate);
|
||||
this.state = {
|
||||
groupedItems: this.groupItems(props.itemsForDay)
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
|
@ -64,12 +63,6 @@ export class Day extends Component {
|
|||
componentWillReceiveProps (nextProps) {
|
||||
this.props.deregisterAnimatable('day', this, this.itemUniqueIds());
|
||||
this.props.registerAnimatable('day', this, nextProps.animatableIndex, this.itemUniqueIds(nextProps));
|
||||
|
||||
this.setState((state) => {
|
||||
return {
|
||||
groupedItems: this.groupItems(nextProps.itemsForDay)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
|
@ -78,12 +71,55 @@ export class Day extends Component {
|
|||
|
||||
itemUniqueIds (props = this.props) { return props.itemsForDay.map(item => item.uniqueId); }
|
||||
|
||||
groupItems = (items) => groupBy(items, item => {
|
||||
return (item.context && (item.context.type+item.context.id)) || 'Notes';
|
||||
})
|
||||
|
||||
hasItems () {
|
||||
return !!Object.keys(this.state.groupedItems).length;
|
||||
return this.props.itemsForDay && this.props.itemsForDay.length > 0;
|
||||
}
|
||||
|
||||
renderGrouping(groupKey, groupItems, index) {
|
||||
const courseInfo = groupItems[0].context || {};
|
||||
return (
|
||||
<Grouping
|
||||
title={courseInfo.title}
|
||||
image_url={courseInfo.image_url}
|
||||
color={courseInfo.color}
|
||||
timeZone={this.props.timeZone}
|
||||
updateTodo={this.props.updateTodo}
|
||||
items={groupItems}
|
||||
animatableIndex={this.props.animatableIndex * 100 + index + 1}
|
||||
url={courseInfo.url}
|
||||
key={groupKey}
|
||||
theme={{
|
||||
titleColor: courseInfo.color || null
|
||||
}}
|
||||
toggleCompletion={this.props.toggleCompletion}
|
||||
currentUser={this.props.currentUser}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderGroupings () {
|
||||
const groupings = [];
|
||||
let currGroupItems;
|
||||
let currGroupKey;
|
||||
const nItems = this.props.itemsForDay.length;
|
||||
|
||||
for (let i = 0; i < nItems; ++i) {
|
||||
let item = this.props.itemsForDay[i];
|
||||
let groupKey = (item.context && item.context.id) ? `${item.context.type}${item.context.id}` : 'Notes';
|
||||
if (groupKey !== currGroupKey) {
|
||||
if (currGroupKey) { // emit the grouping we've been working
|
||||
groupings.push(this.renderGrouping(currGroupKey, currGroupItems, groupings.length));
|
||||
}
|
||||
// start new grouping
|
||||
currGroupKey = groupKey;
|
||||
currGroupItems = [item];
|
||||
} else {
|
||||
currGroupItems.push(item);
|
||||
}
|
||||
}
|
||||
// the last groupings// emit the grouping we've been working
|
||||
groupings.push(this.renderGrouping(currGroupKey, currGroupItems, groupings.length));
|
||||
return groupings;
|
||||
}
|
||||
|
||||
render () {
|
||||
|
@ -113,28 +149,7 @@ export class Day extends Component {
|
|||
<div>
|
||||
{
|
||||
(this.hasItems()) ? (
|
||||
Object.keys(this.state.groupedItems).map((cid, groupIndex) => {
|
||||
const groupItems = this.state.groupedItems[cid];
|
||||
const courseInfo = groupItems[0].context || {};
|
||||
return (
|
||||
<Grouping
|
||||
title={courseInfo.title}
|
||||
image_url={courseInfo.image_url}
|
||||
color={courseInfo.color}
|
||||
timeZone={this.props.timeZone}
|
||||
updateTodo={this.props.updateTodo}
|
||||
items={groupItems}
|
||||
animatableIndex={this.props.animatableIndex * 100 + groupIndex + 1}
|
||||
url={courseInfo.url}
|
||||
key={cid}
|
||||
theme={{
|
||||
titleColor: courseInfo.color || null
|
||||
}}
|
||||
toggleCompletion={this.props.toggleCompletion}
|
||||
currentUser={this.props.currentUser}
|
||||
/>
|
||||
);
|
||||
})
|
||||
this.renderGroupings()
|
||||
) : (
|
||||
<View
|
||||
textAlign="center"
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
import MockDate from 'mockdate';
|
||||
import moment from 'moment-timezone';
|
||||
import {initialize} from '../../../utilities/alertUtils';
|
||||
import {ScrollToLoadedToday} from '../scroll-to-loaded-today';
|
||||
import {createAnimation, mockRegistryEntry} from './test-utils';
|
||||
import {startLoadingPastUntilTodaySaga, gotDaysSuccess} from '../../../actions/loading-actions';
|
||||
|
@ -25,6 +26,11 @@ const TZ = 'Asia/Tokyo';
|
|||
|
||||
beforeAll(() => {
|
||||
MockDate.set('2018-04-15', TZ);
|
||||
initialize({
|
||||
visualSuccessCallback: jest.fn(),
|
||||
visualErrorCallback: jest.fn(),
|
||||
srAlertCallback: jest.fn()
|
||||
});
|
||||
});
|
||||
afterAll(() => {
|
||||
MockDate.reset();
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
import MockDate from 'mockdate';
|
||||
import moment from 'moment-timezone';
|
||||
import {initialize} from '../../../utilities/alertUtils';
|
||||
import {ScrollToToday} from '../scroll-to-today';
|
||||
import {createAnimation, mockRegistryEntry} from './test-utils';
|
||||
|
||||
|
@ -25,6 +26,11 @@ const TZ = 'Asia/Tokyo';
|
|||
|
||||
beforeAll(() => {
|
||||
MockDate.set('2018-04-15', TZ);
|
||||
initialize({
|
||||
visualSuccessCallback: jest.fn(),
|
||||
visualErrorCallback: jest.fn(),
|
||||
srAlertCallback: jest.fn()
|
||||
});
|
||||
});
|
||||
afterAll(() => {
|
||||
MockDate.reset();
|
||||
|
|
|
@ -58,7 +58,7 @@ export function scrollAndFocusTodayItem (manager, todayElem) {
|
|||
}
|
||||
|
||||
function findTodayOrNext (registry) {
|
||||
const today = moment();
|
||||
const today = moment().startOf('day');
|
||||
const todayOrNextItem = registry.getAllItemsSorted().find(item => {
|
||||
return item.component.props.date >= today;
|
||||
});
|
||||
|
|
|
@ -24,10 +24,10 @@ describe('getting new items', () => {
|
|||
const initialState = [];
|
||||
|
||||
const gotDataAction = gotItemsSuccess([
|
||||
{ id: 'fourth', dateBucketMoment: moment.tz('2017-04-29', 'UTC') },
|
||||
{ id: 'second', dateBucketMoment: moment.tz('2017-04-28', 'UTC') },
|
||||
{ id: 'first', dateBucketMoment: moment.tz('2017-04-27', 'UTC') },
|
||||
{ id: 'third', dateBucketMoment: moment.tz('2017-04-28', 'UTC') },
|
||||
{ id: 'fourth', date: moment.tz('2017-04-29', 'UTC'), dateBucketMoment: moment.tz('2017-04-29', 'UTC'), title: 'aaa' },
|
||||
{ id: 'second', date: moment.tz('2017-04-28', 'UTC'), dateBucketMoment: moment.tz('2017-04-28', 'UTC'), title: 'aaa' },
|
||||
{ id: 'first', date: moment.tz('2017-04-27', 'UTC'), dateBucketMoment: moment.tz('2017-04-27', 'UTC'), title: 'aaa' },
|
||||
{ id: 'third', date: moment.tz('2017-04-28', 'UTC'), dateBucketMoment: moment.tz('2017-04-28', 'UTC'), title: 'bbb' },
|
||||
]);
|
||||
|
||||
const newState = daysReducer(initialState, gotDataAction);
|
||||
|
@ -38,9 +38,9 @@ describe('getting new items', () => {
|
|||
]);
|
||||
|
||||
const nextGotDataAction = gotItemsSuccess([
|
||||
{id: 'fifth', dateBucketMoment: moment.tz('2017-04-29', 'UTC')},
|
||||
{id: 'zeroth', dateBucketMoment: moment.tz('2017-04-26', 'UTC')},
|
||||
{id: 'second', with: 'new data', dateBucketMoment: moment.tz('2017-04-28', 'UTC')}
|
||||
{id: 'fifth', date: moment.tz('2017-04-29', 'UTC'), dateBucketMoment: moment.tz('2017-04-29', 'UTC'), title: 'aaa'},
|
||||
{id: 'zeroth', date: moment.tz('2017-04-26', 'UTC') , dateBucketMoment: moment.tz('2017-04-26', 'UTC'), title: 'aaa'},
|
||||
{id: 'second', with: 'new data',date: moment.tz('2017-04-28', 'UTC'), dateBucketMoment: moment.tz('2017-04-28', 'UTC'), title: 'aaa'}
|
||||
]);
|
||||
const mergedState = daysReducer(newState, nextGotDataAction);
|
||||
expect(mergedState).toMatchObject([
|
||||
|
@ -55,11 +55,11 @@ describe('getting new items', () => {
|
|||
describe('saving planner items', () => {
|
||||
it('adds new items to the day', () => {
|
||||
const initialState = [
|
||||
['2017-04-27', [{id: '42', dateBucketMoment: moment.tz('2017-04-27', 'UTC')}]],
|
||||
['2017-04-27', [{id: '42', date: moment.tz('2017-04-27', 'UTC'), dateBucketMoment: moment.tz('2017-04-27', 'UTC'), title: 'aaa'}]],
|
||||
];
|
||||
const newState = daysReducer(initialState, {
|
||||
type: 'SAVED_PLANNER_ITEM',
|
||||
payload: {item: {id: '43', dateBucketMoment: moment.tz('2017-04-27', 'UTC')}},
|
||||
payload: {item: {id: '43', date: moment.tz('2017-04-27', 'UTC'), dateBucketMoment: moment.tz('2017-04-27', 'UTC'), title: 'aaa'}},
|
||||
});
|
||||
expect(newState).toMatchObject([
|
||||
['2017-04-27', [
|
||||
|
@ -73,19 +73,20 @@ describe('saving planner items', () => {
|
|||
// more than one item to make sure edited item gets merged, not deleted and re-added
|
||||
const initialState = [
|
||||
['2017-04-27', [
|
||||
{dateBucketMoment: moment.tz('2017-04-27', 'UTC'), id: '42', title: 'an event'},
|
||||
{dateBucketMoment: moment.tz('2017-04-27', 'UTC'), id: '43', title: 'another event'},
|
||||
{date: moment.tz('2017-04-27', 'UTC'), dateBucketMoment: moment.tz('2017-04-27', 'UTC'), id: '42', title: 'aaa event'},
|
||||
{date: moment.tz('2017-04-27', 'UTC'), dateBucketMoment: moment.tz('2017-04-27', 'UTC'), id: '43', title: 'bbb event'},
|
||||
]],
|
||||
];
|
||||
const newState = daysReducer(initialState, {
|
||||
type: 'SAVED_PLANNER_ITEM',
|
||||
payload: {item: {dateBucketMoment: moment.tz( '2017-04-27', 'UTC'), id: '42', title: 'renamed event'}},
|
||||
payload: {item: {date: moment.tz( '2017-04-27', 'UTC'), dateBucketMoment: moment.tz( '2017-04-27', 'UTC'), id: '42', title: 'ccc event'}},
|
||||
});
|
||||
expect(newState).toMatchObject([
|
||||
['2017-04-27', [
|
||||
{id: '42', title: 'renamed event'},
|
||||
{id: '43', title: 'another event'},
|
||||
]],
|
||||
|
||||
expect(newState[0][0]).toEqual('2017-04-27');
|
||||
// new title, and resorted
|
||||
expect(newState[0][1]).toMatchObject([
|
||||
{id: '43', title: 'bbb event'},
|
||||
{id: '42', title: 'ccc event'},
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
import { handleActions } from 'redux-actions';
|
||||
import { formatDayKey } from '../utilities/dateUtils';
|
||||
import { findPlannerItemById } from '../utilities/storeUtils';
|
||||
import { daysToDaysHash, daysHashToDays, mergeDaysIntoDaysHash, itemsToDays } from '../utilities/daysUtils';
|
||||
import { daysToDaysHash, daysHashToDays, mergeDaysIntoDaysHash, itemsToDays, groupAndSortDayItems } from '../utilities/daysUtils';
|
||||
|
||||
function savedPlannerItem (state, action) {
|
||||
if (action.error) return state;
|
||||
|
@ -57,6 +57,12 @@ function _deletePlannerItem(state, doomedPlannerItem) {
|
|||
function gotDaysSuccess (state, days) {
|
||||
const oldDaysHash = daysToDaysHash(state);
|
||||
const mergedDaysHash = mergeDaysIntoDaysHash(oldDaysHash, days);
|
||||
days.forEach(d => {
|
||||
const dayKey = d[0];
|
||||
const dayItems = mergedDaysHash[dayKey].slice(0); // copy items array for this day
|
||||
groupAndSortDayItems(dayItems);
|
||||
mergedDaysHash[dayKey] = dayItems;
|
||||
});
|
||||
return daysHashToDays(mergedDaysHash);
|
||||
}
|
||||
|
||||
|
|
|
@ -302,38 +302,6 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`transformApiToInternalItem extracts and transforms the proper data for an announcement response 1`] = `
|
||||
Object {
|
||||
"completed": false,
|
||||
"context": Object {
|
||||
"color": "#abffaa",
|
||||
"id": "1",
|
||||
"image_url": "blah_url",
|
||||
"inform_students_of_overdue_submissions": true,
|
||||
"title": "blah",
|
||||
"type": "Course",
|
||||
"url": undefined,
|
||||
},
|
||||
"course_id": undefined,
|
||||
"date": "2017-05-15T16:32:34Z",
|
||||
"dateBucketMoment": "2018-03-27T00:00:00.000Z",
|
||||
"html_url": "/courses/1/discussion_topics/10",
|
||||
"id": "1",
|
||||
"newActivity": false,
|
||||
"overrideAssignId": 9,
|
||||
"overrideId": null,
|
||||
"points": undefined,
|
||||
"status": Object {
|
||||
"unread_count": 1,
|
||||
},
|
||||
"title": "",
|
||||
"toggleAPIPending": false,
|
||||
"type": "Announcement",
|
||||
"uniqueId": "announcement-1",
|
||||
"unread_count": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transformApiToInternalItem extracts and transforms the proper data for an ungraded discussion reponse with an unread count 1`] = `
|
||||
Object {
|
||||
"completed": false,
|
||||
|
@ -408,7 +376,7 @@ Object {
|
|||
"url": undefined,
|
||||
},
|
||||
"course_id": "1",
|
||||
"date": "2017-06-21T18:58:51Z",
|
||||
"date": "2017-06-21T18:58:51.000Z",
|
||||
"dateBucketMoment": "2017-06-21T18:58:51.000Z",
|
||||
"details": "asdfasdfasdf",
|
||||
"id": 14,
|
||||
|
@ -424,7 +392,7 @@ Object {
|
|||
"completed": false,
|
||||
"context": Object {},
|
||||
"course_id": null,
|
||||
"date": "2017-06-21T18:58:51Z",
|
||||
"date": "2017-06-21T18:58:51.000Z",
|
||||
"dateBucketMoment": "2017-06-21T18:58:51.000Z",
|
||||
"details": "asdfasdfasdf",
|
||||
"id": 14,
|
||||
|
|
|
@ -403,20 +403,6 @@ describe('transformApiToInternalItem', () => {
|
|||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('extracts and transforms the proper data for an announcement response', () => {
|
||||
const apiResponse = makeApiResponse({
|
||||
plannable_type: 'announcement',
|
||||
plannable: makeDiscussionTopic({ // TODO: Discussion topic is probably fine for now to simulate this, but probably should change later
|
||||
due_at: undefined,
|
||||
todo_date: undefined,
|
||||
unread_count: 1
|
||||
})
|
||||
});
|
||||
|
||||
const result = transformApiToInternalItem(apiResponse, courses, groups, 'UTC');
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('extracts and transforms the ID for a wiki page repsonse', () => {
|
||||
const apiResponse = makeApiResponse({
|
||||
plannable_type: 'wiki_page',
|
||||
|
|
|
@ -19,12 +19,14 @@
|
|||
import {
|
||||
mergeNewItemsIntoDays, mergeNewItemsIntoDaysHash, mergeDaysIntoDaysHash, mergeDaysHashes,
|
||||
itemsToDaysHash, daysToDaysHash, itemsToDays, daysToItems, mergeItems, purgeDuplicateDays,
|
||||
mergeDays, daysHashToDays,
|
||||
mergeDays, daysHashToDays, groupAndSortDayItems,
|
||||
} from '../daysUtils';
|
||||
|
||||
function mockItem (date = '2017-12-18', opts = {}) {
|
||||
return {
|
||||
date: date,
|
||||
dateBucketMoment: date,
|
||||
title: 'aaa',
|
||||
...opts,
|
||||
};
|
||||
}
|
||||
|
@ -32,10 +34,10 @@ function mockItem (date = '2017-12-18', opts = {}) {
|
|||
describe('mergeNewItemsIntoDays', () => {
|
||||
it('merges', () => {
|
||||
const newItems = [
|
||||
mockItem('2017-12-18', {id: 1, name: 'merged item'}),
|
||||
mockItem('2017-12-19', {id: 2, name: 'new item'}),
|
||||
mockItem('2017-12-18', {id: 1, title: 'merged item'}),
|
||||
mockItem('2017-12-19', {id: 2, title: 'new item'}),
|
||||
];
|
||||
const oldItems = [mockItem('2017-12-18', {id: 3, name: 'old item'})];
|
||||
const oldItems = [mockItem('2017-12-18', {id: 3, title: 'old item'})];
|
||||
const oldDays = [['2017-12-18', oldItems]];
|
||||
const result = mergeNewItemsIntoDays(oldDays, newItems);
|
||||
expect(result).toEqual([
|
||||
|
@ -86,10 +88,10 @@ describe('mergeDaysIntoDaysHash', () => {
|
|||
describe('mergeNewItemsIntoDaysHash', () => {
|
||||
it('merges', () => {
|
||||
const newItems = [
|
||||
mockItem('2017-12-18', {id: 1, name: 'merged item'}),
|
||||
mockItem('2017-12-19', {id: 2, name: 'new item'}),
|
||||
mockItem('2017-12-18', {id: 1, title: 'merged item'}),
|
||||
mockItem('2017-12-19', {id: 2, title: 'new item'}),
|
||||
];
|
||||
const oldItems = [mockItem('2017-12-18', {id: 3, name: 'old item'})];
|
||||
const oldItems = [mockItem('2017-12-18', {id: 3, title: 'old item'})];
|
||||
const oldDaysHash = {'2017-12-18': oldItems};
|
||||
const result = mergeNewItemsIntoDaysHash(oldDaysHash, newItems);
|
||||
expect(result).toEqual({
|
||||
|
@ -103,10 +105,10 @@ describe('mergeNewItemsIntoDaysHash', () => {
|
|||
describe('mergeDaysHashes', () => {
|
||||
it('merges', () => {
|
||||
const newDaysHash = {
|
||||
'2017-12-18': [mockItem('2017-12-18', {id: 1, name: 'merged item'})],
|
||||
'2017-12-19': [mockItem('2017-12-19', {id: 2, name: 'new item'})],
|
||||
'2017-12-18': [mockItem('2017-12-18', {id: 1, title: 'merged item'})],
|
||||
'2017-12-19': [mockItem('2017-12-19', {id: 2, title: 'new item'})],
|
||||
};
|
||||
const oldItems = [mockItem('2017-12-18', {id: 3, name: 'old item'})];
|
||||
const oldItems = [mockItem('2017-12-18', {id: 3, title: 'old item'})];
|
||||
const oldDaysHash = {'2017-12-18': oldItems};
|
||||
const result = mergeDaysHashes(oldDaysHash, newDaysHash);
|
||||
expect(result).toEqual({
|
||||
|
@ -192,11 +194,11 @@ describe('daysToItems', () => {
|
|||
describe('mergeItems', () => {
|
||||
it('merges', () => {
|
||||
const oldItems = [
|
||||
mockItem('2017-12-18', {id: 1, name: 'to be replaced'}),
|
||||
mockItem('2017-12-18', {id: 1, title: 'to be replaced'}),
|
||||
mockItem('2017-12-18', {id: 2}),
|
||||
];
|
||||
const newItems = [
|
||||
mockItem('2017-12-18', {id: 1, name: 'replacement'}),
|
||||
mockItem('2017-12-18', {id: 1, title: 'replacement'}),
|
||||
mockItem('2017-12-19', {id: 3})];
|
||||
const result = mergeItems(oldItems, newItems);
|
||||
expect(result).toEqual([newItems[0], oldItems[1], newItems[1]]);
|
||||
|
@ -218,3 +220,70 @@ describe('purgeDuplicateDays', () => {
|
|||
expect(result).not.toBe(oldDays); // no mutation
|
||||
});
|
||||
});
|
||||
|
||||
describe('groupAndSortDayItems', () => {
|
||||
it('groups and sorts courses by title with ToDos at end', () => {
|
||||
const items = [
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '1'}),
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '2', context: {type: 'Course', id: '1', title: 'ZZZ Course'}}),
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '3', context: {type: 'Course', id: '2', title: 'AAA Course'}}),
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '4', context: {type: 'Course', id: '1', title: 'ZZZ Course'}}),
|
||||
];
|
||||
const result = groupAndSortDayItems(items);
|
||||
expect(result).toMatchObject([
|
||||
{id: '3'}, {id: '2'}, {id: '4'}, {id: '1'}
|
||||
]);
|
||||
});
|
||||
|
||||
it('sorts by context type+id if missing title', () => {
|
||||
const items = [
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '1'}),
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '2', context: {type: 'Course', id: '1'}}),
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '3', context: {type: 'Course', id: '2'}}),
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '4', context: {type: 'Course', id: '1'}}),
|
||||
];
|
||||
const result = groupAndSortDayItems(items);
|
||||
expect(result).toMatchObject([
|
||||
{id: '2'}, {id: '4'}, {id: '3'}, {id: '1'}
|
||||
]);
|
||||
});
|
||||
|
||||
it('sorts items with same time by title', () => {
|
||||
const items = [
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '1'}),
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '2', title: 'zzz', context: {type: 'Course', id: '1', title: 'Math'}}),
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '3', context: {type: 'Course', id: '2', title: 'English'}}),
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '4', title: 'aaa', context: {type: 'Course', id: '1', title: 'Math'}}),
|
||||
];
|
||||
const result = groupAndSortDayItems(items);
|
||||
expect(result).toMatchObject([
|
||||
{id: '3'}, {id: '4'}, {id: '2'}, {id: '1'}
|
||||
]);
|
||||
});
|
||||
|
||||
it('sorts items with same time by title with numbers', () => {
|
||||
const items = [
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '1', title: 'x 1'}),
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '3', title: 'x 21'}),
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '2', title: 'x 3'}),
|
||||
];
|
||||
const result = groupAndSortDayItems(items);
|
||||
expect(result).toMatchObject([
|
||||
{id: '1'}, {id: '2'}, {id: '3'}
|
||||
]);
|
||||
});
|
||||
|
||||
it('sorts items by time', () => {
|
||||
const items = [
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '1'}),
|
||||
mockItem('2017-12-05T12:00:00Z', {id: '2', context: {type: 'Course', id: '1', title: 'Math'}}),
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '3', context: {type: 'Course', id: '2', title: 'English'}}),
|
||||
mockItem('2017-12-05T11:00:00Z', {id: '4', context: {type: 'Course', id: '1', title: 'Math'}}),
|
||||
];
|
||||
const result = groupAndSortDayItems(items);
|
||||
expect(result).toMatchObject([
|
||||
{id: '3'}, {id: '4'}, {id: '2'}, {id: '1'}
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -42,9 +42,6 @@ const getItemDetailsFromPlannable = (apiResponse, timeZone) => {
|
|||
if (plannable_type === 'discussion_topic' || plannable_type === 'announcement') {
|
||||
details.unread_count = plannable.unread_count;
|
||||
}
|
||||
if (plannable_type === 'announcement' && !details.date) {
|
||||
details.date = plannable.delayed_post_at || plannable.posted_at;
|
||||
}
|
||||
|
||||
if (plannable_type === 'planner_note') {
|
||||
details.details = plannable.details;
|
||||
|
@ -53,6 +50,7 @@ const getItemDetailsFromPlannable = (apiResponse, timeZone) => {
|
|||
if (plannable_type === 'calendar_event') {
|
||||
details.allDay = plannable.all_day
|
||||
}
|
||||
|
||||
return details;
|
||||
};
|
||||
|
||||
|
@ -137,7 +135,7 @@ export function transformPlannerNoteApiToInternalItem (plannerItemApiResponse, c
|
|||
course_id: plannerNote.course_id,
|
||||
context: context,
|
||||
title: plannerNote.title,
|
||||
date: plannerNote.todo_date,
|
||||
date: moment.tz(plannerNote.todo_date, timeZone),
|
||||
details: plannerNote.details,
|
||||
completed: false
|
||||
};
|
||||
|
|
|
@ -94,3 +94,48 @@ export function purgeDuplicateDays (oldDays, newDays) {
|
|||
newDays.forEach(day => { delete purgedDaysHash[day[0]]; });
|
||||
return daysHashToDays(purgedDaysHash);
|
||||
}
|
||||
|
||||
// sort the items:
|
||||
// First by grouping (alpha by course or group title, followed by the Notes (aka To Dos)
|
||||
// Then by due-time for each item w/in the grouping.
|
||||
export function groupAndSortDayItems (items) {
|
||||
return items.sort(orderItems);
|
||||
}
|
||||
|
||||
// ----- grouping and sorting helpers -----
|
||||
const cmpopts = {numeric: true};
|
||||
const locale =(window.ENV && window.ENV.LOCALE) || 'en';
|
||||
|
||||
// order items by their grouping
|
||||
function getItemGroupTitle(item) {
|
||||
if (item.context && item.context.id) { // edited items have an empty context, so look for the id too
|
||||
return item.context.title || `${item.context.type}${item.context.id}`;
|
||||
}
|
||||
return 'Notes';
|
||||
}
|
||||
|
||||
function orderItemsByGrouping (a, b) {
|
||||
let namea = getItemGroupTitle(a);
|
||||
let nameb = getItemGroupTitle(b);
|
||||
if (namea.localeCompare(nameb, locale, cmpopts) === 0) return 0;
|
||||
if (namea === 'Notes') return 1;
|
||||
if (nameb === 'Notes') return -1;
|
||||
return namea.localeCompare(nameb, locale, cmpopts);
|
||||
}
|
||||
|
||||
// order items by time, then title
|
||||
function orderItemsByTimeAndTitle (a, b) {
|
||||
if (a.date.valueOf() === b.date.valueOf()) {
|
||||
return a.title.localeCompare(b.title, locale, cmpopts);
|
||||
}
|
||||
return a.date < b.date ? -1 : 1;
|
||||
}
|
||||
|
||||
// order items
|
||||
function orderItems (a, b) {
|
||||
let order = orderItemsByGrouping(a, b);
|
||||
if (order === 0) {
|
||||
order = orderItemsByTimeAndTitle(a, b);
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue