Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create new class for DateRangePicker state internals #619

Merged

Conversation

leebyp
Copy link
Contributor

@leebyp leebyp commented Feb 4, 2017

The current way that we handle the displayMonth and in the state in DateRangePicker makes the code pretty unreadable if you do the obvious extension to the state as in #575.

Want to see how folks feel about creating a new class with all the comparison and helper methods. Caveat is that in the edge cases, you can end up cloning and recreating a lot of classes, but they're just functions anyway so shouldn't hit any perf problems.

This change along with the comments in the blocks from #575 should make things a lot easier to parse.

NB. Want some feedback if this is an awful idea before I clean up the duplication and un-disable the tests

@leebyp
Copy link
Contributor Author

leebyp commented Feb 7, 2017

@palantir/blueprint i'm gonna keep going ahead along these lines if this looks good

@llorca llorca requested review from cmslewis and giladgray February 7, 2017 23:36
export function getDateNextMonth(date: Date): Date {
const nextMonth = getNextMonth([date.getMonth(), date.getFullYear()]);
return new Date(nextMonth[1], nextMonth[0]);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Missing newline?


// returns 1 if left < right
// returns -1 if left > right
// returns 0 if left === right
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comparator scheme is backward, no? Should return -1 if the left one is lesser, +1 if the left one is greater.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going for "in-order is truthy", but agree that following standard convention is easier to understand. Updated


type MonthAndYear = [number, number];

function getPreviousMonth([month, year]: MonthAndYear): MonthAndYear {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this function isn't referenced anywhere. Do we still need it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return month === Months.JANUARY ? [Months.DECEMBER, year - 1] : [month - 1, year];
}

function getNextMonth([month, year]: MonthAndYear): MonthAndYear {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -16,7 +16,7 @@ import * as Errors from "../src/common/errors";
import { Months } from "../src/common/months";
import { Classes as DateClasses, DateRange, DateRangePicker, IDateRangePickerProps } from "../src/index";

describe("<DateRangePicker>", () => {
xdescribe("<DateRangePicker>", () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reasoning behind xdescribe vs. describe.skip? Reads more clearly if it'll behave equivalently for you.

Copy link
Contributor

@giladgray giladgray Feb 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i prefer describe.skip for readability. also we have lint rules banning describe.skip so you won't accidentally commit merge it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh nice, i can't find those rules - is it possible to also lint for the xit and xdescribe variants?

private date: Date;

constructor (month: number, year: number) {
if (month !== null && year !== null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if they are optional then mark them as such.
constructor(month?: number, year?: number)


type MonthAndYear = [number, number];

function getPreviousMonth([month, year]: MonthAndYear): MonthAndYear {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return month === Months.JANUARY ? [Months.DECEMBER, year - 1] : [month - 1, year];
}

function getNextMonth([month, year]: MonthAndYear): MonthAndYear {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

public isAfter(displayMonth: DisplayMonth): boolean {
return compareDisplayMonth(this, displayMonth) === -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do > 0 and < 0--more readable and robust, as comparators can return other positive/negative values with same semantics.


import { Months } from "./months";

export class DisplayMonth {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i might advocate for calling this MonthAndYear cuz that's what it is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup! made a big rename

rightDisplayMonth: rightDisplay[0],
rightDisplayYear: rightDisplay[1],
});
private setDisplay(leftDisplayMonth: DisplayMonth, rightDisplayMonth: DisplayMonth) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function doesn't seem very helpful anymore. could just inline it when used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's useful mainly so the setState in the other methods don't become a pain to read because they're named potentialXXXX. It's also nice to limit the places we have setState in this complicated component.

let potentialLeftDisplay: DisplayMonth = [state.leftDisplayMonth, state.leftDisplayYear];
let potentialRightDisplay: DisplayMonth = [state.rightDisplayMonth, state.rightDisplayYear];
let potentialLeftDisplay: DisplayMonth = state.leftDisplayMonth.clone();
let potentialRightDisplay: DisplayMonth = state.rightDisplayMonth.clone();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def don't need to explicitly type these vars

if (compareDisplayMonth(potentialLeftDisplay, potentialRightDisplay) !== DisplayMonthOrder.IN_ORDER) {
potentialLeftDisplay = getPreviousMonth(potentialRightDisplay);
const nextValueEndMonthDisplay: DisplayMonth =
new DisplayMonth(nextValueEnd.getMonth(), nextValueEnd.getFullYear());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks like a .clone()

const nextValueStartMonthDisplay: DisplayMonth =
new DisplayMonth(nextValueStart.getMonth(), nextValueStart.getFullYear());
const nextValueEndMonthDisplay: DisplayMonth =
new DisplayMonth(nextValueEnd.getMonth(), nextValueEnd.getFullYear());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are both .clones?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this and above are converting Dates to MonthAndYears

@blueprint-bot
Copy link

rename DisplayMonth to MonthAndYear

Preview: docs | landing | table
Coverage: core | datetime

@blueprint-bot
Copy link

switch displaymonth comparator to conventional return values

Preview: docs | landing | table
Coverage: core | datetime

if (firstMonth > secondMonth) {
return 1;
}
}
Copy link
Contributor

@giladgray giladgray Feb 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (firstYear === secondYear) {
  return firstMonth - secondMonth; // positive number means first is larger
} else {
  return firstYear - secondYear;   // negative number means second is larger
}

Copy link
Contributor Author

@leebyp leebyp Feb 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well aint that neat, updated!

@@ -415,53 +415,51 @@ export class DateRangePicker
* and rectify appropriately.
*/
private handleLeftYearSelectChange = (leftDisplayYear: number) => {
let potentialLeftDisplay = new DisplayMonth(this.state.leftDisplayMonth.getMonth(), leftDisplayYear);
let potentialLeftMonthAndYear = new MonthAndYear(this.state.leftMonthAndYear.getMonth(), leftDisplayYear);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok we get it, there's a month and a year! 😛

leftDisplayMonth: potentialLeftDisplay,
rightDisplayMonth: potentialRightDisplay,
leftMonthAndYear: potentialLeftMonthAndYear,
rightMonthAndYear: potentialRightMonthAndYear,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but actually renaming all these variables makes this thing dang near impossible to read. what if all the variables called it a View instead of MonthAndYear? so much shorter and more digestible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even better! the logic's pretty readable now

@blueprint-bot
Copy link

change DateRangePicker internal state name

Preview: docs | landing | table
Coverage: core | datetime

@blueprint-bot
Copy link

simplify compare month and year

Preview: docs | landing | table
Coverage: core | datetime

@blueprint-bot
Copy link

fix utils function

Preview: docs | landing | table
Coverage: core | datetime

@leebyp leebyp merged commit cc3d5e4 into bl/independent-daterangepicker-months Feb 13, 2017
@leebyp leebyp deleted the bl/daterangepicker-state-refactor branch February 13, 2017 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants