Skip to content

Commit 2ca574c

Browse files
rogier2012martijnrusschen
authored andcommitted
Quarter year picker (Hacker0x01#1877)
* Add basic quarter picker as a variation of month picker - added similar tests and css * Add basic quarter picker as a variation of month picker - added similar tests and css * Added date utils tests * Reverted accidental change of month picker test
1 parent 2b8732a commit 2ca574c

File tree

11 files changed

+468
-24
lines changed

11 files changed

+468
-24
lines changed

docs-site/src/components/Examples/index.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ import TimeInput from "../../examples/timeInput";
6161
import StrictParsing from "../../examples/strictParsing";
6262
import MonthPicker from "../../examples/monthPicker";
6363
import RangeMonthPicker from "../../examples/rangeMonthPicker";
64+
import QuarterPicker from "../../examples/quarterPicker";
65+
import RangeQuarterPicker from "../../examples/rangeQuarterPicker";
6466

6567
import "./style.scss";
6668
import "react-datepicker/dist/react-datepicker.css";
@@ -303,6 +305,14 @@ export default class exampleComponents extends React.Component {
303305
{
304306
title: "Range Month Picker",
305307
component: RangeMonthPicker
308+
},
309+
{
310+
title: "Quarter Picker",
311+
component: QuarterPicker
312+
},
313+
{
314+
title: "Range Quarter Picker",
315+
component: RangeQuarterPicker
306316
}
307317
];
308318

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
() => {
2+
const [startDate, setStartDate] = useState(new Date());
3+
return (
4+
<DatePicker
5+
selected={startDate}
6+
onChange={date => setStartDate(date)}
7+
dateFormat="yyyy, QQQ"
8+
showQuarterYearPicker
9+
/>
10+
);
11+
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
() => {
2+
const [startDate, setStartDate] = useState(new Date("2014/02/08"));
3+
const [endDate, setEndDate] = useState(new Date("2014/07/08"));
4+
return (
5+
<>
6+
<DatePicker
7+
selected={startDate}
8+
onChange={date => setStartDate(date)}
9+
selectsStart
10+
startDate={startDate}
11+
endDate={endDate}
12+
dateFormat="yyyy, QQQ"
13+
showQuarterYearPicker
14+
/>
15+
<DatePicker
16+
selected={endDate}
17+
onChange={date => setEndDate(date)}
18+
selectsEnd
19+
startDate={startDate}
20+
endDate={endDate}
21+
dateFormat="yyyy, QQQ"
22+
showQuarterYearPicker
23+
/>
24+
</>
25+
);
26+
};

src/calendar.jsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export default class Calendar extends React.Component {
8787
showTimeSelect: PropTypes.bool,
8888
showTimeInput: PropTypes.bool,
8989
showMonthYearPicker: PropTypes.bool,
90+
showQuarterYearPicker: PropTypes.bool,
9091
showTimeSelectOnly: PropTypes.bool,
9192
timeFormat: PropTypes.string,
9293
timeIntervals: PropTypes.number,
@@ -361,7 +362,7 @@ export default class Calendar extends React.Component {
361362

362363
let clickHandler = this.decreaseMonth;
363364

364-
if (this.props.showMonthYearPicker) {
365+
if (this.props.showMonthYearPicker || this.props.showQuarterYearPicker) {
365366
clickHandler = this.decreaseYear;
366367
}
367368

@@ -376,7 +377,7 @@ export default class Calendar extends React.Component {
376377
className={classes.join(" ")}
377378
onClick={clickHandler}
378379
>
379-
{this.props.showMonthYearPicker
380+
{this.props.showMonthYearPicker || this.props.showQuarterYearPicker
380381
? this.props.previousYearButtonLabel
381382
: this.props.previousMonthButtonLabel}
382383
</button>
@@ -421,7 +422,7 @@ export default class Calendar extends React.Component {
421422

422423
let clickHandler = this.increaseMonth;
423424

424-
if (this.props.showMonthYearPicker) {
425+
if (this.props.showMonthYearPicker || this.props.showQuarterYearPicker) {
425426
clickHandler = this.increaseYear;
426427
}
427428

@@ -436,7 +437,7 @@ export default class Calendar extends React.Component {
436437
className={classes.join(" ")}
437438
onClick={clickHandler}
438439
>
439-
{this.props.showMonthYearPicker
440+
{this.props.showMonthYearPicker || this.props.showQuarterYearPicker
440441
? this.props.nextYearButtonLabel
441442
: this.props.nextMonthButtonLabel}
442443
</button>
@@ -609,7 +610,7 @@ export default class Calendar extends React.Component {
609610
}}
610611
className="react-datepicker__month-container"
611612
>
612-
{!this.props.showMonthYearPicker
613+
{!this.props.showMonthYearPicker && !this.props.showQuarterYearPicker
613614
? this.props.renderCustomHeader
614615
? this.renderCustomHeader({ monthDate, i })
615616
: this.renderDefaultHeader({ monthDate, i })
@@ -647,6 +648,7 @@ export default class Calendar extends React.Component {
647648
renderDayContents={this.props.renderDayContents}
648649
disabledKeyboardNavigation={this.props.disabledKeyboardNavigation}
649650
showMonthYearPicker={this.props.showMonthYearPicker}
651+
showQuarterYearPicker={this.props.showQuarterYearPicker}
650652
/>
651653
</div>
652654
);

src/date_utils.js

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ import getHours from "date-fns/getHours";
1919
import getDay from "date-fns/getDay";
2020
import getDate from "date-fns/getDate";
2121
import getMonth from "date-fns/getMonth";
22+
import getQuarter from "date-fns/getQuarter";
2223
import getYear from "date-fns/getYear";
2324
import getTime from "date-fns/getTime";
2425
import setSeconds from "date-fns/setSeconds";
2526
import setMinutes from "date-fns/setMinutes";
2627
import setHours from "date-fns/setHours";
2728
import setMonth from "date-fns/setMonth";
29+
import setQuarter from "date-fns/setQuarter";
2830
import setYear from "date-fns/setYear";
2931
import min from "date-fns/min";
3032
import max from "date-fns/max";
@@ -34,6 +36,7 @@ import differenceInCalendarWeeks from "date-fns/differenceInCalendarWeeks";
3436
import startOfDay from "date-fns/startOfDay";
3537
import startOfWeek from "date-fns/startOfWeek";
3638
import startOfMonth from "date-fns/startOfMonth";
39+
import startOfQuarter from "date-fns/startOfQuarter";
3740
import startOfYear from "date-fns/startOfYear";
3841
import endOfDay from "date-fns/endOfDay";
3942
import endOfWeek from "date-fns/endOfWeek";
@@ -42,6 +45,7 @@ import dfIsEqual from "date-fns/isEqual";
4245
import dfIsSameDay from "date-fns/isSameDay";
4346
import dfIsSameMonth from "date-fns/isSameMonth";
4447
import dfIsSameYear from "date-fns/isSameYear";
48+
import dfIsSameQuarter from "date-fns/isSameQuarter";
4549
import isAfter from "date-fns/isAfter";
4650
import isBefore from "date-fns/isBefore";
4751
import isWithinInterval from "date-fns/isWithinInterval";
@@ -168,7 +172,7 @@ export function setTime(date, { hour = 0, minute = 0, second = 0 }) {
168172
return setHours(setMinutes(setSeconds(date, second), minute), hour);
169173
}
170174

171-
export { setMonth, setYear };
175+
export { setMonth, setYear, setQuarter };
172176

173177
// ** Date Getters **
174178

@@ -178,6 +182,7 @@ export {
178182
getMinutes,
179183
getHours,
180184
getMonth,
185+
getQuarter,
181186
getYear,
182187
getDay,
183188
getDate,
@@ -212,6 +217,10 @@ export function getStartOfMonth(date) {
212217
return startOfMonth(date);
213218
}
214219

220+
export function getStartOfQuarter(date) {
221+
return startOfQuarter(date);
222+
}
223+
215224
export function getStartOfToday() {
216225
return startOfDay(newDate());
217226
}
@@ -256,6 +265,14 @@ export function isSameMonth(date1, date2) {
256265
}
257266
}
258267

268+
export function isSameQuarter(date1, date2) {
269+
if (date1 && date2) {
270+
return dfIsSameQuarter(date1, date2);
271+
} else {
272+
return !date1 && !date2;
273+
}
274+
}
275+
259276
export function isSameDay(date1, date2) {
260277
if (date1 && date2) {
261278
return dfIsSameDay(date1, date2);
@@ -345,6 +362,10 @@ export function getMonthShortInLocale(month, locale) {
345362
return formatDate(setMonth(newDate(), month), "LLL", locale);
346363
}
347364

365+
export function getQuarterShortInLocale(quarter, locale) {
366+
return formatDate(setQuarter(newDate(), quarter), "QQQ", locale);
367+
}
368+
348369
// ** Utils for some components **
349370

350371
export function isDayDisabled(
@@ -402,6 +423,38 @@ export function isMonthinRange(startDate, endDate, m, day) {
402423
}
403424
}
404425

426+
export function isQuarterDisabled(
427+
quarter,
428+
{ minDate, maxDate, excludeDates, includeDates, filterDate } = {}
429+
) {
430+
return (
431+
isOutOfBounds(quarter, { minDate, maxDate }) ||
432+
(excludeDates &&
433+
excludeDates.some(excludeDate => isSameQuarter(quarter, excludeDate))) ||
434+
(includeDates &&
435+
!includeDates.some(includeDate => isSameQuarter(quarter, includeDate))) ||
436+
(filterDate && !filterDate(newDate(quarter))) ||
437+
false
438+
);
439+
}
440+
441+
export function isQuarterInRange(startDate, endDate, q, day) {
442+
const startDateYear = getYear(startDate);
443+
const startDateQuarter = getQuarter(startDate);
444+
const endDateYear = getYear(endDate);
445+
const endDateQuarter = getQuarter(endDate);
446+
const dayYear = getYear(day);
447+
if (startDateYear === endDateYear && startDateYear === dayYear) {
448+
return startDateQuarter <= q && q <= endDateQuarter;
449+
} else if (startDateYear < endDateYear) {
450+
return (
451+
(dayYear === startDateYear && startDateQuarter <= q) ||
452+
(dayYear === endDateYear && endDateQuarter >= q) ||
453+
(dayYear < endDateYear && dayYear > startDateYear)
454+
);
455+
}
456+
}
457+
405458
export function isOutOfBounds(day, { minDate, maxDate } = {}) {
406459
return (
407460
(minDate && differenceInCalendarDays(day, minDate) < 0) ||

src/index.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ export default class DatePicker extends React.Component {
149149
shouldCloseOnSelect: PropTypes.bool,
150150
showTimeInput: PropTypes.bool,
151151
showMonthYearPicker: PropTypes.bool,
152+
showQuarterYearPicker: PropTypes.bool,
152153
showTimeSelect: PropTypes.bool,
153154
showTimeSelectOnly: PropTypes.bool,
154155
timeFormat: PropTypes.string,
@@ -197,6 +198,7 @@ export default class DatePicker extends React.Component {
197198
showTimeSelect: false,
198199
showTimeInput: false,
199200
showMonthYearPicker: false,
201+
showQuarterYearPicker: false,
200202
strictParsing: false,
201203
timeIntervals: 30,
202204
timeCaption: "Time",
@@ -694,6 +696,7 @@ export default class DatePicker extends React.Component {
694696
onMonthMouseLeave={this.props.onMonthMouseLeave}
695697
showTimeInput={this.props.showTimeInput}
696698
showMonthYearPicker={this.props.showMonthYearPicker}
699+
showQuarterYearPicker={this.props.showQuarterYearPicker}
697700
>
698701
{this.props.children}
699702
</WrappedCalendar>

0 commit comments

Comments
 (0)