I am looking to a solution for my ReactJS project.
In a property page I want to display a Date Range Picker with the availability of the property.
By running a query with Postman I get the availability from the calendar with the following format, although there is no problem for me to manipulate the array in order to fit the requirements for the date range picker.
How to display inside the date range picker the blocked days so they are not clickable. I already tried with the DateRangePicker of rsuite and storybook but no luck for me. For the rsuite the data should have the following format:
It will depend on the date range picker you decide to use (or if you write your own) - a quick look at this component's API, for example, will tell you that it has a disabledDates: Date[] prop that you can use to disable certain dates.
The way I managed to do it was to get the data from the API.
Manipulated and syntax in a way the DateRangePicker could import it via a function.
axios(config)
.then(function (response) {
//console.log(JSON.stringify(response.data));
calendar= response.data.calendar;
console.log(calendar);
var highlighted = [];
var disabled_days=[];
for(var i=0;i<calendar.length;i++) {
var item = calendar[i];
if(item.status === 'available') {
highlighted.push(new Date(item.date));
//console.log(item.date);
}
else{
disabled_days.push(new Date(item.date));
}
};
modifiers = {
disabled: disabled_days,
highlight: highlighted
}
self.setState({
modifiers: modifiers})
//console.log(modifiers);
})
.catch(function (error) {
console.log(error);
});
Then I used the package 'react-calendar' and import it to my node project.
npm i 'react-calendar' --save
Then I used the component Calendar as I have import it via the following command:
import Calendar from '../Components/CalendarRangePicker';
...
<Calendar modifiers={modifiers}/>
...
CalendarRangePicker.js
import { useState } from 'react';
import Calendar from 'react-calendar';
import 'react-calendar/dist/Calendar.css';
function CalendarRangePicker(props){
const [value, onChange] = useState(new Date());
const dataNotYetFetched = useState();
// disabled some days until I fetched the data...
var disabledDates = [
new Date(2021, 7, 1),
new Date(2021, 7, 2),
];
//console.log(disabledDates);
var modifiers = null;
if(props.modifiers != null) {
modifiers = props.modifiers;
console.log(modifiers);
disabledDates = modifiers.disabled;
}
return (
<div>
<Calendar
// Make calendar not viewable for previous months
minDate={new Date()}
// Whether to show two months
showDoubleView = {false}
ActiveStartDate = {new Date()}
returnValue={"range"}
// settings for the calendar
onChange={onChange}
value={value}
selectRange={true}
locale="en-US"
autofocus={false}
// disabled dates. Got data from channel manager
tileDisabled={({date, view}) =>
(view === 'month') && // Block day tiles only
disabledDates.some(disabledDate =>
date.getFullYear() === disabledDate.getFullYear() &&
date.getMonth() === disabledDate.getMonth() &&
date.getDate() === disabledDate.getDate()
)}
/>
</div>
);
}
export default CalendarRangePicker;
Related
I'm currently using react-calender
I'm trying to add a class to the tiles in the calendar for those dates that are found in the array. However, I'm not sure how can i add these dates in the arrays into the calender as it only accepts one date const event = new Date("2022-10-20");
i tried with the followings and it does not work :-
import { addDays, differenceInCalendarDays } from "date-fns";
import Calendar from "react-calendar";
import "react-calendar/dist/Calendar.css";
const all_event_dates = [ '2023-03-24', '2022-12-30', '2022-11-05', '2022-10-20' ]
const alleventDates = new Date(all_event_dates);
const highlightedDates = [alleventDates];
function isSameDay(a, b) {
return differenceInCalendarDays(a, b) === 0;
}
function tileClassName({ date, view }) {
if (
view === "month" &&
highlightedDates.find((dDate) => isSameDay(dDate, date))
) {
// Or: return "highlight background";
return ["add-new-class", "false"];
}
}
<Calendar
onChange={onChange}
value={value}
tileClassName={tileClassName}
/>
Can anyone help me what am i missing in here?
I have a MUI date picker in my React app that I want to use with serverside data.
I'm returning the correct data in my console log that I pass in my useState hook const [availableDate, setAvailableDate] = useState({}); and now want to pass the selected date into the picker:
returned JSON
const data = [
{
date: '05/05/21',
timeSlots: [
{
end: '11:00',
start: '12:00'
}
]
},
{
date: '05/05/24',
timeSlots: [
{
end: '13:00',
start: '14:00'
}
]
}
];
Date Picker
const [availableDate, setAvailableDate] = useState({});
const [filteredData, setFilteredData] = useState(availableDate);
//set current date as default
var curr = new Date();
function setDate(dat) {
let datt = {
date: {// ... returend date},
start: '11:40',
end: '13:00',
};
service.stepDate.setCvData(datt);
}
curr.setDate(curr.getDate());
var date = curr.toISOString().substr(0, 10);
Date Picker
I tried mapping the array data in my date picker but this just returns multiple pickers.
{availableDates.map((index) => (
<div className="calendarWrapper">
<form noValidate>
<TextField
key={index.id}
minDate={today}
id="date"
type="date"
onChange={setDate}
defaultValue={date}
/>
</form>
</div>
))}
How do I extract the selected date ex: date: "2021/05/24" from the json and pass it into my setDate() function?
First of all, onChange interface is the following
onChange(e) {
// e.target.value
}
so you won't be able to get your date from e directly.
Also date is an object, which can't be {} initially, null could be one option, or new Date().
following code disabled all the previous dates including today, but I want to disable all the Sundays and array of specific days in ant design date picker.
< DatePicker size = "large"
format = "DD/MM/YYYY"
nChange = {
this.onDate1Change
}
disabledDate = {
current => {
return current && current < moment().endOf('day');
}
}
/>
To start we have a look at antd's Datepicker example in the depending docs.
Disable all Sundays
We use the moment.js lib to check the days and disable all sundays (here it is the first == zero).
E.g.:
function disabledDate(current) {
// Can not select sundays and predfined days
return moment(current).day() === 0
}
Disable specific days
First we define an array of our dates and then check if a converted day is in our disabled array.
const disabledDates = ["2020-07-21", "2020-07-23"];
function disabledDate(current) {
// Can not select Sundays and predefined days
return disabledDates.find(date => date === moment(current).format("YYYY-MM-DD"));
}
Putting all together
Now we can combine both solutions. A working example can be found in this CodeSandbox.
E.g.:
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import moment from "moment";
import { DatePicker } from "antd";
const disabledDates = ["2020-07-21", "2020-07-23"];
function disabledDate(current) {
// Can not select Sundays and predefined days
return (
moment(current).day() === 0 ||
disabledDates.find(date => date === moment(current).format("YYYY-MM-DD"))
);
}
ReactDOM.render(
<>
<DatePicker
format="YYYY-MM-DD HH:mm:ss"
disabledDate={disabledDate}
showTime={{ defaultValue: moment("00:00:00", "HH:mm:ss") }}
/>
</>,
document.getElementById("container")
);
If you don't want to use the "Moment" library, you can do as I did:
const disabledDate = (current) => {
return (
current < Date.now() ||
(new Date(current).getDay() === 0 ||
new Date(current).getDay() === 6)
);
};
I'm using a date/time picker that I found on https://material-ui-pickers.dev/ and wanted to use it with the moment.js library. I'm having some issues. I have a form that collects a start time and an end time. I wanted to use the moment.js "diff" method to calculate the difference in hours. I keep getting "20.4234254" or similar, regardless of what dates & times I enter.
The format of the date as it's being held in state and managed by moment.js is:
"Wed Jul 08 2020 21:51:23 GMT-0700 (Pacific Daylight Time)".
import React, { useState, useEffect } from 'react';
import MomentUtils from '#date-io/moment';
import {
DatePicker,
TimePicker,
DateTimePicker,
MuiPickersUtilsProvider,
} from '#material-ui/pickers';
import moment from 'moment';
function DateFormField() {
const [startDate, startTime] = useState(new Date());
const [endDate, endTime] = useState(new Date());
const [duration, setDuration] = useState("");
const timeCalc = (startDate, endDate) => {
var start = moment(startDate);
var end = moment(endDate);
console.log(end.diff(start, "hours", true) + ' hours');
}
return (
<MuiPickersUtilsProvider utils={MomentUtils}>
<DateTimePicker value={startDate} onChange={startTime} helperText="Start Time" />
<DateTimePicker value={endDate} onChange={endTime} helperText="End Time" />
<button onClick={timeCalc}>Time Duration: {duration}</button>
</MuiPickersUtilsProvider>
);
}
export default DateFormField;
Issue
I can't get this code to run in a sandbox (interacting with the DateTimePicker for some reason throws a utils.getYearText is not a function TypeError), but I think I know what the issue is.
You define timeCalc to consume two arguments, startDate and endDate
const timeCalc = (startDate, endDate) => {
var start = moment(startDate);
var end = moment(endDate);
console.log(end.diff(start, "hours", true) + ' hours');
}
but in the button to trigger it you simply attach the function to the onClick handler, so it is actually only passed the event object as the first argument and undefined for the second.
<button onClick={timeCalc}>Time Duration: {duration}</button>
I then tested timeCalc manually in the function body by passing it the startDate and endDate state values and it (presumably) correctly returns 0 hours, as would be expected from two nearly identical timestamps.
const timeCalc = (startDate, endDate) => {
var start = moment(startDate);
var end = moment(endDate);
console.log(end.diff(start, "hours", true) + " hours");
};
timeCalc(new Date(), new Date());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js"></script>
Solution
Either remove the arguments to timeCalc so the referenced startDate and endDate values will be the ones in global component scope
const timeCalc = () => {
var start = moment(startDate);
var end = moment(endDate);
console.log(end.diff(start, "hours", true) + ' hours');
}
Or explicitly pass the state values to the callback
<button onClick={() => timeCalc(startDate, endDate)}>
Time Duration: {duration}
</button>
My application can get data from user. For this i have different inputs. One of my inputs is date Picker.
<Form.Item name="Picker" label="date">
<RangePicker
showTime={{ format: "HH:mm" }}
format="YYYY-MM-DD HH:mm"
onChange={onChange2}
onOk={onOk}
/>
</Form.Item>
The issue appear when i try to access data after clicking on submit button. In console i have all data from each input, but from RangePicker, the data is not structured, and i get:
Picker: Array[2]
0: Moment
1: Moment
The problem is that i can access this array, and display on fron end. How to do this?
link to my app: https://codesandbox.io/s/form-methods-ant-design-demo-kbwgk
Try this
import moment from 'moment'
const onFinish = values => {
const startDate = moment(values.Picker[0]).format("YYYY-MM-DD HH:mm");
const endDate = moment(values.Picker[1]).format("YYYY-MM-DD HH:mm");
console.log(startDate, endDate)
};
I got it,
on your rangepicker use
onFinish instead of onOk
<RangePicker
showTime={{ format: "HH:mm" }}
format="YYYY-MM-DD HH:mm"
onChange={onChange2}
onFinish={onFinish}
/>
working as specified
you press Ok twice , so the first onOk still doesnt include the second part of the range
sorry for not giving professional answer
Since you are getting it as an array of moment objects,try using moment js for formatting the moment js according to your needs
https://codesandbox.io/s/form-methods-ant-design-demo-sy4uq
function onOk(value) {
const start = moment(value[0]).format("YYYY-MM-DD HH:mm:ss");
const end = moment(value[1]).format("YYYY-MM-DD HH:mm:ss");
console.log(start, end);
}
const onFinish = values => {
const start = moment(values.Picker[0]).format("YYYY-MM-DD HH:mm:ss");
const end = moment(values.Picker[1]).format("YYYY-MM-DD HH:mm:ss");
console.log(start, end)
};