CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/next/components/misc/date-range.tsx
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2022 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { DatePicker } from "antd";
7
import dayjs from "dayjs";
8
import { CSSProperties, useState } from "react";
9
import { DateRangeType, Date0 } from "@cocalc/util/types/store";
10
11
interface Props {
12
onChange?: (x: DateRangeType) => void;
13
style?: CSSProperties;
14
noPast?: boolean; // if true, don't allow dates in the past
15
maxDaysInFuture?: number; // don't allow dates this far in the future from now
16
disabled?: boolean;
17
initialValues?: DateRangeType;
18
suffix?: string;
19
}
20
21
export default function DateRange(props: Props) {
22
const {
23
onChange,
24
style,
25
noPast,
26
maxDaysInFuture,
27
disabled = false,
28
initialValues = [undefined, undefined],
29
suffix,
30
} = props;
31
32
const [dateRange, setDateRange] = useState<DateRangeType>(initialValues);
33
34
const presets = [
35
{ label: "Day", value: [dayjs(), dayjs().add(1, "day")] },
36
{ label: "Week", value: [dayjs(), dayjs().add(1, "week")] },
37
{ label: "Month", value: [dayjs(), dayjs().add(1, "month")] },
38
{ label: "Year", value: [dayjs(), dayjs().add(1, "year")] },
39
{
40
label: "+ Hour",
41
value: [dayjs(dateRange[0]), dayjs(dateRange[0]).add(1, "hour")],
42
},
43
{
44
label: "+ Day",
45
value: [dayjs(dateRange[0]), dayjs(dateRange[0]).add(1, "day")],
46
},
47
{
48
label: "+ Week",
49
value: [dayjs(dateRange[0]), dayjs(dateRange[0]).add(1, "week")],
50
},
51
{
52
label: "+ Month",
53
value: [dayjs(dateRange[0]), dayjs(dateRange[0]).add(1, "month")],
54
},
55
{
56
label: "+ Three Months",
57
value: [dayjs(dateRange[0]), dayjs(dateRange[0]).add(3, "months")],
58
},
59
{
60
label: "+ Four Months",
61
value: [dayjs(dateRange[0]), dayjs(dateRange[0]).add(4, "months")],
62
},
63
];
64
65
return (
66
<div style={style}>
67
<DatePicker.RangePicker
68
changeOnBlur
69
disabled={disabled}
70
allowEmpty={[true, true]}
71
renderExtraFooter={() => (
72
<div style={{ marginBottom: "-15px" }}>
73
<div>
74
Select start and end dates above, with the help of the presets
75
below:
76
</div>
77
<ul>
78
<li style={{ marginTop: "-15px" }}>
79
Week = one week starting today
80
</li>
81
<li style={{ marginTop: "-15px" }}>
82
+Week = one week, starting from the selected start date
83
</li>
84
</ul>
85
</div>
86
)}
87
presets={presets as any}
88
value={
89
[
90
dateRange[0] ? dayjs(dateRange[0]) : undefined,
91
dateRange[1] ? dayjs(dateRange[1]) : undefined,
92
] as any
93
}
94
onChange={(value) => {
95
const now = dayjs();
96
// Ensure start is the later of now or the start of the selected day
97
const start = value?.[0]
98
? dayjs(value[0]).isBefore(now)
99
? now.toDate()
100
: dayjs(value[0]).startOf("day").toDate()
101
: undefined;
102
// Set end of day, but only modify if there's a value
103
const end = value?.[1]
104
? dayjs(value[1]).endOf("day").subtract(1, "minute").toDate()
105
: undefined;
106
const x: [Date0, Date0] = [start, end];
107
setDateRange(x);
108
onChange?.(x);
109
}}
110
disabledDate={
111
noPast || maxDaysInFuture
112
? (date) => {
113
if (!date) return false;
114
if (noPast && date <= dayjs().subtract(1, "day")) return true;
115
if (
116
maxDaysInFuture &&
117
date >= dayjs().add(maxDaysInFuture, "days")
118
) {
119
return true;
120
}
121
return false;
122
}
123
: undefined
124
}
125
/>
126
{suffix && <span style={{ marginLeft: "5px" }}>{suffix}</span>}
127
</div>
128
);
129
}
130
131