cronofy-elements
Advanced tools
Comparing version 1.41.0 to 1.42.0
{ | ||
"name": "cronofy-elements", | ||
"version": "1.41.0", | ||
"version": "1.42.0", | ||
"description": "Fast track scheduling with Cronofy's embeddable UI Elements", | ||
@@ -5,0 +5,0 @@ "main": "build/npm/CronofyElements.js", |
@@ -8,4 +8,5 @@ import moment from "moment-timezone"; | ||
getLocalDayFromUtc, | ||
removeMonthFromLoading, | ||
} from "../utils/slots"; | ||
import { parseTimeSlots } from "../utils/calendar"; | ||
import { getMonthsInDisplay, parseTimeSlots } from "../utils/calendar"; | ||
@@ -52,2 +53,18 @@ export const statusReducer = (state, action) => { | ||
case "ERROR_LOADING_SLOTS": { | ||
const notification = { | ||
notification: { | ||
type: "error", | ||
message: | ||
"There was a problem with your availability query. Slots for the month of " + | ||
action.month + | ||
" could not be loaded.", | ||
body: action.error.body, | ||
}, | ||
}; | ||
const monthsLoading = removeMonthFromLoading(state.monthsLoading, action.month); | ||
state.callback(notification); | ||
return { ...state, monthsLoading }; | ||
} | ||
case "NO_SLOTS_FOUND": { | ||
@@ -62,2 +79,3 @@ return { ...state, columnView: "no-slots" }; | ||
hasPrev: state.monthlyView.hasPrev, | ||
monthsInView: state.monthlyView.monthsInView, | ||
days: parseTimeSlots({ | ||
@@ -85,2 +103,3 @@ slots: state.slots, | ||
const availableDaysSet = new Set([...state.availableDays, ...availableDays]); | ||
const monthsLoading = removeMonthFromLoading(state.monthsLoading, action.month); | ||
@@ -90,2 +109,3 @@ return { | ||
availableDays: [...availableDaysSet].sort(), | ||
monthsLoading, | ||
slots: slotsObject, | ||
@@ -141,2 +161,3 @@ slotFetchCount: state.slotFetchCount + 1, | ||
hasPrev: actionMonthObject.isAfter(state.startDateObject, "month"), | ||
monthsInView: getMonthsInDisplay(action.month, state.startDay), | ||
days: parseTimeSlots({ | ||
@@ -182,2 +203,3 @@ tzid: action.tzid, | ||
hasPrev: state.monthlyView.hasPrev, | ||
monthsInView: state.monthlyView.monthsInView, | ||
days: parseTimeSlots({ | ||
@@ -184,0 +206,0 @@ slots: state.slots, |
import React, { useMemo } from "react"; | ||
import moment from "moment-timezone"; | ||
import { getMonthObjectsFromQuery, parseTzList, getInitialSelectedTzid } from "./utils/slots"; | ||
import { parseTimeSlots } from "./utils/calendar"; | ||
import { | ||
getMonthObjectsFromQuery, | ||
parseTzList, | ||
getInitialSelectedTzid, | ||
getMonthsLoadingFromQuery, | ||
} from "./utils/slots"; | ||
import { getMonthsInDisplay, parseTimeSlots } from "./utils/calendar"; | ||
@@ -32,2 +37,4 @@ import Wrapper from "./Wrapper"; | ||
const currentMonth = currentMonthObject.format("YYYY-MM"); | ||
const monthsLoading = getMonthsLoadingFromQuery(options.query, options.tzid); | ||
const monthsInView = getMonthsInDisplay(currentMonth, options.config.startDay); | ||
@@ -38,2 +45,3 @@ const monthlyView = { | ||
hasPrev: currentMonthObject.isAfter(startDateObject, "month"), | ||
monthsInView, | ||
days: parseTimeSlots({ | ||
@@ -63,2 +71,3 @@ slots: {}, | ||
monthlyView, | ||
monthsLoading, | ||
selected: false, | ||
@@ -65,0 +74,0 @@ startDay: options.config.startDay, |
@@ -95,2 +95,25 @@ import moment from "moment-timezone"; | ||
export const getMonthsInDisplay = (month, startDay) => { | ||
const monthObject = moment(month, "YYYY-MM"); | ||
const daysInMonth = monthObject.daysInMonth(); | ||
const offset = weekDayOffset(monthObject, startDay); | ||
const result = [month]; | ||
const daysLength = daysInMonth + offset; | ||
//Add prev month if in display... | ||
if (offset > 0) { | ||
const prevMonth = monthObject.clone().add(-1, "months").format("YYYY-MM"); | ||
result.push(prevMonth); | ||
} | ||
// Add next month if in display | ||
if (daysLength < 42) { | ||
const nextMonth = monthObject.clone().add(1, "months").format("YYYY-MM"); | ||
result.push(nextMonth); | ||
} | ||
return result; | ||
}; | ||
export const parseTimeSlots = ({ slots, month, tzid, startDay }) => { | ||
@@ -97,0 +120,0 @@ //Get array of available days |
@@ -5,2 +5,3 @@ import moment from "moment-timezone"; | ||
import { uniqueItems, humanizeTzName } from "../../../helpers/utils"; | ||
import { errorMessages } from "../../../helpers/logging"; | ||
@@ -36,2 +37,30 @@ import { defaultTimeZones } from "./tz-list"; | ||
export const getMonthsLoadingFromQuery = (query, tzid) => { | ||
if (!query.query_periods || !query.query_periods.length) { | ||
return [ | ||
{ | ||
month: moment.tz().format("YYYY-MM"), | ||
loading: true, | ||
}, | ||
]; | ||
} | ||
const monthStrings = getMonthsFromQuery(query.query_periods, tzid); | ||
const monthObjects = monthStrings.map(month => { | ||
return { | ||
month, | ||
loading: true, | ||
}; | ||
}); | ||
return monthObjects; | ||
}; | ||
export const removeMonthFromLoading = (monthsLoading, month) => { | ||
const monthPos = monthsLoading.findIndex(m => m.month === month); | ||
const newMonthsLoading = [...monthsLoading]; | ||
if (monthsLoading && monthPos >= 0) { | ||
newMonthsLoading[monthPos]["loading"] = false; | ||
} | ||
return newMonthsLoading; | ||
}; | ||
export const getCurrentMonth = query => ({ | ||
@@ -80,2 +109,10 @@ month: moment.tz().format("YYYY-MM"), | ||
).then(res => { | ||
if (res.errors) { | ||
throw { | ||
type: 422, | ||
message: errorMessages[422].message, | ||
body: res.errors, | ||
docsSlug: errorMessages[422].docsSlug, | ||
}; | ||
} | ||
// This will intentionally throw an error if the | ||
@@ -82,0 +119,0 @@ // result is not in the correct format: |
@@ -1,2 +0,2 @@ | ||
import React, { useEffect, useRef } from "react"; | ||
import React, { useEffect, useRef, useState } from "react"; | ||
import moment from "moment"; | ||
@@ -11,2 +11,3 @@ | ||
import Loading from "./Loading"; | ||
import LoadingCalendar from "./LoadingCalendar"; | ||
import NoSlotsFound from "./NoSlotsFound"; | ||
@@ -24,2 +25,4 @@ import SlotsList from "./SlotsList"; | ||
const [loadingCalendar, setLoadingCalendar] = useState(true); | ||
const confirmButtonRef = useRef(); | ||
@@ -32,3 +35,3 @@ | ||
const fetchMonthSlots = query => { | ||
const fetchMonthSlots = (query, month) => { | ||
return getSlots({ | ||
@@ -38,9 +41,18 @@ query, | ||
tzid: status.tzid, | ||
}).then(res => { | ||
dispatchStatus({ | ||
type: "SET_SLOTS", | ||
slots: res, | ||
tzid: tz.selectedTzid.tzid, | ||
}) | ||
.then(res => { | ||
dispatchStatus({ | ||
type: "SET_SLOTS", | ||
slots: res, | ||
tzid: tz.selectedTzid.tzid, | ||
month: month, | ||
}); | ||
}) | ||
.catch(res => { | ||
dispatchStatus({ | ||
type: "ERROR_LOADING_SLOTS", | ||
error: res, | ||
month: month, | ||
}); | ||
}); | ||
}); | ||
}; | ||
@@ -51,7 +63,7 @@ | ||
// Get slots for current month | ||
fetchMonthSlots(currentMonth.query) | ||
fetchMonthSlots(currentMonth.query, currentMonth.month) | ||
.then(() => { | ||
// Get slots for remianing months | ||
const remainingMonths = status.months.filter(month => !month.current); | ||
remainingMonths.forEach(month => fetchMonthSlots(month.query)); | ||
remainingMonths.forEach(month => fetchMonthSlots(month.query, month.month)); | ||
}) | ||
@@ -75,3 +87,3 @@ .catch(error => { | ||
if (!injectionPoint.isBetween(firstDay, lastDay)) { | ||
if (!injectionPoint.isBetween(firstDay, lastDay, "day", "[]")) { | ||
return; | ||
@@ -153,2 +165,16 @@ } | ||
useEffect(() => { | ||
if (status.monthsLoading) { | ||
for (let month of status.monthlyView.monthsInView) { | ||
const monthLoading = status.monthsLoading.find(m => m.month === month); | ||
if (monthLoading && monthLoading.loading) { | ||
setLoadingCalendar(true); | ||
return; | ||
} else { | ||
setLoadingCalendar(false); | ||
} | ||
} | ||
} | ||
}, [status.monthlyView, status.monthsLoading]); | ||
return ( | ||
@@ -167,2 +193,3 @@ <section className={theme.classBuilder()} style={theme.customProperties}> | ||
<Calendar /> | ||
{loadingCalendar && <LoadingCalendar />} | ||
</div> | ||
@@ -169,0 +196,0 @@ <div className={theme.classBuilder("column--right")}> |
@@ -7,2 +7,3 @@ { | ||
"duration_label": "Duration", | ||
"loading_calendar": "Loading Available Days", | ||
"minutes": "minutes", | ||
@@ -9,0 +10,0 @@ "nav_previous_month": "navigate to previous month", |
@@ -16,7 +16,12 @@ import { statusReducer } from "../../../src/js/components/DateTimePicker/contexts/status-reducer"; | ||
getMonthObjectsFromQuery, | ||
getMonthsLoadingFromQuery, | ||
} from "../../../src/js/components/DateTimePicker/utils/slots"; | ||
import { parseTimeSlots } from "../../../src/js/components/DateTimePicker/utils/calendar"; | ||
import { | ||
getMonthsInDisplay, | ||
parseTimeSlots, | ||
} from "../../../src/js/components/DateTimePicker/utils/calendar"; | ||
import moment from "moment"; | ||
const months = getMonthObjectsFromQuery(testQuery, "Europe/London"); | ||
const monthsLoading = getMonthsLoadingFromQuery(testQuery, "Europe/London"); | ||
@@ -27,2 +32,3 @@ const testMonthlySlots = months.map((month, i) => ({ | ||
hasPrev: i > 0 ? true : false, | ||
monthsInView: getMonthsInDisplay(month.month, "sunday"), | ||
days: parseTimeSlots({ | ||
@@ -46,2 +52,3 @@ slots: testSlotsObject, | ||
monthlyView: testMonthlyView, | ||
monthsLoading, | ||
selected: { | ||
@@ -146,2 +153,66 @@ start: "2021-09-29T08:00:00Z", | ||
it("ERROR_LOADING_SLOTS", async () => { | ||
const callbackSpy = jest.spyOn(startingState, "callback"); | ||
const oldState = { | ||
...startingState, | ||
monthsLoading: [ | ||
{ month: "2021-09", loading: true }, | ||
{ month: "2021-10", loading: true }, | ||
], | ||
}; | ||
const error = { | ||
body: { | ||
"query_periods[0].end": [ | ||
{ | ||
key: "errors.max_date_exceeded", | ||
description: "date is too far in the future", | ||
}, | ||
], | ||
}, | ||
}; | ||
const result = statusReducer(oldState, { | ||
type: "ERROR_LOADING_SLOTS", | ||
error, | ||
month: "2021-10", | ||
}); | ||
const expectedNotification = { | ||
notification: { | ||
type: "error", | ||
message: | ||
"There was a problem with your availability query. Slots for the month of 2021-10 could not be loaded.", | ||
body: { | ||
"query_periods[0].end": [ | ||
{ | ||
key: "errors.max_date_exceeded", | ||
description: "date is too far in the future", | ||
}, | ||
], | ||
}, | ||
}, | ||
}; | ||
const newMonthsLoading = [ | ||
{ | ||
month: "2021-09", | ||
loading: true, | ||
}, | ||
{ | ||
month: "2021-10", | ||
loading: false, | ||
}, | ||
]; | ||
delete oldState.monthsLoading; | ||
const { monthsLoading, ...newState } = result; | ||
// These values have been updated | ||
expect(monthsLoading).toStrictEqual(newMonthsLoading); | ||
expect(callbackSpy).toHaveBeenCalled(); | ||
expect(callbackSpy).toHaveBeenCalledWith(expectedNotification); | ||
// All other values are unchanged | ||
expect(newState).toStrictEqual(oldState); | ||
}); | ||
it("NO_SLOTS_FOUND", async () => { | ||
@@ -191,5 +262,17 @@ const oldState = { ...startingState }; | ||
slots: testSlotsArray, | ||
month: "2021-09", | ||
tzid: "Europe/London", | ||
}); | ||
const newMonthsLoading = [ | ||
{ | ||
month: "2021-09", | ||
loading: false, | ||
}, | ||
{ | ||
month: "2021-10", | ||
loading: true, | ||
}, | ||
]; | ||
delete oldState.slots; | ||
@@ -199,2 +282,3 @@ delete oldState.availableDays; | ||
delete oldState.slotInjectionPoint; | ||
delete oldState.monthsLoading; | ||
@@ -206,2 +290,3 @@ const { | ||
slotInjectionPoint, | ||
monthsLoading, | ||
...newState | ||
@@ -220,2 +305,3 @@ } = result; | ||
expect(slotInjectionPoint).toBe("2021-09-29"); | ||
expect(monthsLoading).toStrictEqual(newMonthsLoading); | ||
@@ -238,2 +324,3 @@ // All other values are unchanged | ||
slots: testSingleSlotsArray, | ||
month: "2021-09", | ||
tzid: "Europe/London", | ||
@@ -270,7 +357,29 @@ }); | ||
availableDays: ["2021-09-29", "2021-09-30"], | ||
monthsLoading: [ | ||
{ | ||
month: "2021-09", | ||
loading: false, | ||
}, | ||
{ | ||
month: "2021-10", | ||
loading: true, | ||
}, | ||
], | ||
}; | ||
const newMonthsLoading = [ | ||
{ | ||
month: "2021-09", | ||
loading: false, | ||
}, | ||
{ | ||
month: "2021-10", | ||
loading: false, | ||
}, | ||
]; | ||
const result = statusReducer(oldState, { | ||
type: "SET_SLOTS", | ||
slots: testSlotsArrayAdditional, | ||
month: "2021-10", | ||
tzid: "Europe/London", | ||
@@ -283,2 +392,3 @@ }); | ||
delete oldState.availableDays; | ||
delete oldState.monthsLoading; | ||
@@ -290,2 +400,3 @@ const { | ||
availableDays, | ||
monthsLoading, | ||
...newState | ||
@@ -303,2 +414,3 @@ } = result; | ||
]); | ||
expect(monthsLoading).toStrictEqual(newMonthsLoading); | ||
@@ -305,0 +417,0 @@ expect(newState).toStrictEqual(oldState); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
3238907
338
26428