Search code examples
javascriptreactjsmomentjsauth0react-dates

Display when order will be delivered & disable days deliveries can't be made in react-datepicker


I need some help displaying the next available day for delivery based on when a user places an order and what day/s they are eligible to receive an order.

I also need some help disabling/filtering all week days except the delivery day and future delivery day a user is eligible for.

I am using React, React-Datepicker, MomentJS and auth0.

The problem is that a company's delivery trucks go to certain locations on certain days. On Mondays they go to Location 1 and on Tuesdays they go to Location 2 for example.

When getting a new client (aka user) they assign a day/s to that user. So if UserA is located in Location 1 they will be assigned to Mondays and if UserB is located in Location 2 they will be assigned to Tuesdays for example.

This data I get from auth0's user_metadata. So I got data coming in.

I searched and researched and found this post on stackoverflow: https://stackoverflow.com/questions/34979051/find-next-instance-of-a-given-weekday-ie-monday-with-moment-js#:~:text=In%20a%20nutshell%2C%20you%20want,day(1)%20.

It allows me to get the next available day based on the day the user orders.

But I am having trouble figuring out how to apply this to display the message dynamically. Meaning UserA will see information about delivery day based on his data and UserB will see information about delivery day based on his data.

Another problem is that I can filter the weekends using react-datepicker but I don't know how to apply these momentjs functions to react-datepicker for each user.

I created a codesandbox with my progress (not a lot of progress) and I created two users but am stuck.

https://codesandbox.io/embed/dry-violet-trjrq?codemirror=1

Please let me know if I need to provide more information or post the question better.

Here is the link to the github repo if that helps (linking to component where codesandbox code will go):

https://github.com/Chizzah/core-water/blob/master/src/components/tableContainer/tableView.js

Thanks in advance for any help or guidance.


Solution

  • I assume Auth0's user_metadata is individual to each user, and can be accessed within the component. Say you pass user's day of the week for the delivery in user_metadata.delivery

    To make it work with the react-datepicker, you have to have the weekday as a number, with Monday being 1 and Sunday being 7 (the ISO week date standard). You'll then provide only days that are user's delivery weekdays in the calendar dropdown:

    <DatePicker
    filterDate={(date) => date.getDay() === weekdayNo }
     *...your other props*
    />
    

    there might also be a way to do it with excludeDates prop, although in this case that appears to be a less effective option: https://reactdatepicker.com/#example-exclude-dates

    Now if your user_metadata.delivery has values 1-7, you can use it straight up. If it's string values like "Monday", "Sunday", you can parse it to weekday numbers with your Moment.js:

    const weekdayNo = moment().isoWeekday(weekdayString).isoWeekday();
    

    https://momentjscom.readthedocs.io/en/latest/moment/02-get-set/08-iso-weekday/

    otherwise (if it's like "mon", "sun") you might need to write a function that returns the weekday number yourself.

    As I've understood if the user is ordering on his/her delivery weekday, it'll arrive after a week, if not - the next delivery weekday. You can determine that with a function like this

    function calculateDeliveryDate(weekdayNo){
        const todayNo = moment().isoWeekday();
        if (todayNo === weekdayNo) {
          return moment().add(1, "weeks");
        } else if (todayNo < weekdayNo) {
          return moment().add(weekdayNo - todayNo, "days");
        } else if (todayNo > weekdayNo) {
          return moment().add(7 - (todayNo - weekdayNo), "days");
        }   
    };
    

    or refactored with ternaries

    
        const todayNo = moment().isoWeekday();
        const nextWeekdayDate = (todayNo, weekdayNo) => {
          return todayNo < weekdayNo
            ? today.add(weekdayNo - todayNo, "days")
            : today.add(7 - (todayNo - weekdayNo), "days");
        };
    
        return todayNo === weekdayNo
          ? today.add(1, "weeks")
          : nextWeekdayDate(todayNo, weekdayNo);   
        };
    

    This will give you back a date object, so to display it for the user you can format it with moment.js:

    const deliveryDateString = moment(calculateDeliveryDate(weekdayNo)).format("DD MM YYYY", true).toString();
    

    https://momentjs.com/docs/#/displaying/

    best of luck