cronofy-elements
Advanced tools
Comparing version 1.17.8 to 1.18.0
{ | ||
"name": "cronofy-elements", | ||
"version": "1.17.8", | ||
"version": "1.18.0", | ||
"description": "Fast track scheduling with Cronofy's embeddable UI Elements", | ||
@@ -14,2 +14,3 @@ "main": "build/npm/CronofyElements.js", | ||
"dev": "webpack --mode=development --watch", | ||
"dev_analyse": "webpack --mode=development --watch --analyse", | ||
"dev_compat": "webpack --config compat.config.js --mode=development --watch", | ||
@@ -16,0 +17,0 @@ "serve": "npm run build_server && nodemon build/server.js", |
@@ -126,9 +126,10 @@ import React, { useState, useEffect } from "react"; | ||
Promise.all([ | ||
connections.getAvailabilityRules( | ||
options.token, | ||
options.domains.apiDomain, | ||
account.availability_rule_id, | ||
`AvailabilityRules`, | ||
options.demo | ||
), | ||
connections.getAvailabilityRules({ | ||
token: options.token, | ||
api_domain: options.domains.apiDomain, | ||
availability_rule_id: account.availability_rule_id, | ||
element: `AvailabilityRules`, | ||
mock: options.demo, | ||
tzid: options.tzid | ||
}), | ||
connections.getCalendars( | ||
@@ -233,9 +234,9 @@ options.token, | ||
connections | ||
.setAvailabilityRules( | ||
options.token, | ||
options.domains.apiDomain, | ||
rulesRequest, | ||
`AvailabilityRules`, | ||
options.demo | ||
) | ||
.setAvailabilityRules({ | ||
token: options.token, | ||
api_domain: options.domains.apiDomain, | ||
params: rulesRequest, | ||
element: `AvailabilityRules`, | ||
mock: options.demo | ||
}) | ||
.then(res => { | ||
@@ -242,0 +243,0 @@ if (res.errors) { |
@@ -46,3 +46,3 @@ import React, { useState, useEffect } from "react"; | ||
const [theme, setTheme] = useState({ | ||
const [theme, setTheme] = useState(() => ({ | ||
...parseStyleOptions( | ||
@@ -59,8 +59,12 @@ { ...options.styles }, | ||
sizes: { | ||
breakpoints: { | ||
small: 650 | ||
}, | ||
columnWidth: 100, | ||
labelWidth: 60, | ||
columnWidth: 100, | ||
labelWidthSmall: 24, | ||
wrapperWidth: false, | ||
wrapperUnderflow: 0 | ||
} | ||
}); | ||
})); | ||
@@ -105,3 +109,3 @@ const [i18n, setI18n] = useState( | ||
const [slotData, setSlotData] = useState(generateDummySlots()); | ||
const [slotsForPage, setSlotsForPage] = useState( | ||
const [slotsForPage, setSlotsForPage] = useState(() => | ||
getSlotsForPage(slotData, pages.current) | ||
@@ -201,2 +205,17 @@ ); | ||
const handleFreeSelectAvailability = response => { | ||
const slotsWithKeys = addKeysToSlots(response); | ||
setRawData({ ...rawData, ...slotsWithKeys }); | ||
const pagesLoaded = Array.from(Array(pages.total).keys()).map( | ||
i => i + 1 | ||
); | ||
setStatus({ | ||
...status, | ||
error: false, | ||
loading: false, | ||
preloading: false, | ||
pagesLoaded | ||
}); | ||
}; | ||
const handleEmptyAvailability = (res, query) => { | ||
@@ -248,17 +267,16 @@ let notification; | ||
useEffect(() => { | ||
setPages( | ||
generateStaticPages( | ||
options.query.query_periods, | ||
options.config.startDay, | ||
status.tzid | ||
) | ||
); | ||
}, []); | ||
const triggerDataFetching = () => { | ||
if (!error) { | ||
if (status.mode === "free_select") { | ||
const freeSelectQuery = { | ||
...options.query, | ||
start_interval: { minutes: limits.interval } | ||
}; | ||
useEffect(() => { | ||
if (!pages.set) return; | ||
triggerSlotsForPage(); | ||
return handleGetAvailability({ | ||
query: freeSelectQuery, | ||
callback: handleFreeSelectAvailability | ||
}); | ||
} | ||
if (!error) { | ||
let query = { | ||
@@ -277,2 +295,3 @@ ...options.query, | ||
}); | ||
if (croppedQuery.query_periods.length > 0) { | ||
@@ -309,12 +328,41 @@ // Happy Path. | ||
} | ||
}, [limits, pages]); | ||
}; | ||
useEffect(() => { | ||
setPages( | ||
generateStaticPages( | ||
options.query.query_periods, | ||
options.config.startDay, | ||
status.tzid | ||
) | ||
); | ||
}, []); | ||
useEffect(() => { | ||
if (!pages.set) return; | ||
triggerSlotsForPage(); | ||
if (rawData && status.mode === "free_select") { | ||
// We're in free_select and we've already got our rawData, so | ||
// let's reset the loading graphics and bail... | ||
setStatus(status => ({ | ||
...status, | ||
error: false, | ||
loading: false, | ||
preloading: false | ||
})); | ||
return; | ||
} | ||
triggerDataFetching(); | ||
}, [pages]); | ||
useEffect(() => { | ||
triggerSlotsForPage(); | ||
}, [slotData]); | ||
useEffect(() => { | ||
const slotHeightCalc = calculateSlotHeight(limits); | ||
setTheme(t => ({ ...t, slotHeightCalc })); | ||
if (!objectIsEmpty(rawData)) { | ||
if (objectIsEmpty(rawData)) return; | ||
if (status.mode !== "free_select") { | ||
setStatus({ | ||
@@ -326,3 +374,24 @@ ...status, | ||
}); | ||
triggerDataFetching(); | ||
} | ||
if (status.mode === "free_select") { | ||
const slots = generatePageSlots({ | ||
availablePeriods: rawData, | ||
limits, | ||
pages, | ||
tzid: status.tzid, | ||
unrestricted: status.slotSelection === "unrestricted", | ||
freeSelect: status.mode === "free_select" | ||
}); | ||
let updatedSlots = slots.slots; | ||
setSlotData(oldSlots => { | ||
if (status.mode === "free_select") { | ||
// If we're overriding the slots state (with `setSlotData`), then | ||
// We'll need to make sure we persit any "selected" slots. | ||
updatedSlots = checkSelectedState(slots.slots, oldSlots); | ||
} | ||
return updatedSlots; | ||
}); | ||
} | ||
}, [limits]); | ||
@@ -337,13 +406,16 @@ | ||
tzid: status.tzid, | ||
unrestricted: status.slotSelection === "unrestricted" | ||
unrestricted: status.slotSelection === "unrestricted", | ||
freeSelect: status.mode === "free_select" | ||
}); | ||
let updatedSlots = slots.slots; | ||
if (status.mode === "free_select") { | ||
// If we're overriding the slots state (with `setSlotData`), then | ||
// We'll need to make sure we persit any "selected" slots. | ||
updatedSlots = checkSelectedState(slots.slots, slotData); | ||
} | ||
setSlotData(updatedSlots); | ||
setSlotData(oldSlots => { | ||
if (status.mode === "free_select") { | ||
// If we're overriding the slots state (with `setSlotData`), then | ||
// We'll need to make sure we persit any "selected" slots. | ||
updatedSlots = checkSelectedState(slots.slots, oldSlots); | ||
} | ||
return updatedSlots; | ||
}); | ||
} | ||
}, [limits, rawData]); | ||
}, [rawData]); | ||
@@ -350,0 +422,0 @@ return ( |
@@ -30,4 +30,4 @@ import React, { useContext } from "react"; | ||
flex-shrink: 0; | ||
@media (max-width: 650px) { | ||
display: none; | ||
@media (max-width: ${theme.sizes.breakpoints.small}px) { | ||
width: ${theme.sizes.labelWidthSmall}px; | ||
} | ||
@@ -34,0 +34,0 @@ `} |
@@ -25,4 +25,4 @@ import React, { useContext } from "react"; | ||
flex-shrink: 0; | ||
@media (max-width: 650px) { | ||
display: none; | ||
@media (max-width: ${theme.sizes.breakpoints.small}px) { | ||
width: ${theme.sizes.labelWidthSmall}px; | ||
} | ||
@@ -29,0 +29,0 @@ `} |
import React, { useContext, useState } from "react"; | ||
import moment from "moment-timezone"; | ||
import { css, jsx } from "@emotion/core"; | ||
import { I18nContext, ThemeContext, StatusContext } from "./AvailabilityViewer"; | ||
import { ThemeContext, StatusContext } from "./AvailabilityViewer"; | ||
import { LabelsContext } from "./WeekWrapper"; | ||
import LabelItem from "./LabelItem"; | ||
import TimeExpander from "./TimeExpander"; | ||
import TimeSelector from "./TimeSelector"; | ||
@@ -12,3 +14,2 @@ import TimeSelectorTrigger from "./TimeSelectorTrigger"; | ||
const [selectionVisibility, setSelectionVisibility] = useState(false); | ||
const i18n = useContext(I18nContext); | ||
const [status, setStatus] = useContext(StatusContext); | ||
@@ -18,58 +19,10 @@ const [theme, setTheme] = useContext(ThemeContext); | ||
const height = theme.slotHeightCalc.height; | ||
const handleCalendarSelection = () => { | ||
const handleTimeSelection = () => { | ||
setSelectionVisibility(!selectionVisibility); | ||
}; | ||
const labelsOutput = labels.map(label => { | ||
let labelText = null; | ||
const labelsOutput = labels.map((label, i) => ( | ||
<LabelItem key={label.start} label={label} i={i} /> | ||
)); | ||
const localStart = moment | ||
.utc(label.start, "YYYY-MM-DDTHH:mm:00Z") | ||
.tz(status.tzid); | ||
if (label.hour) { | ||
labelText = ( | ||
<span | ||
css={css` | ||
display: block; | ||
width: 100%; | ||
position: absolute; | ||
top: -1px; | ||
right: 4px; | ||
color: ${theme.colors.black}; | ||
line-height: 1; | ||
font-size: 12px; | ||
text-transform: lowercase; | ||
text-align: right; | ||
padding: 0 4px; | ||
@media (max-width: 650px) { | ||
right: auto; | ||
left: 0; | ||
left: ${theme.sizes.wrapperUnderflow}px; | ||
top: 2px; | ||
text-align: left; | ||
} | ||
`} | ||
className={`${theme.prefix}__time-text`} | ||
> | ||
{i18n.f(localStart, "LT").replace(" ", "")} | ||
</span> | ||
); | ||
} | ||
return ( | ||
<div | ||
key={label.start} | ||
css={css` | ||
display: block; | ||
height: ${height}px; | ||
position: relative; | ||
`} | ||
className={`${theme.prefix}__time-label`} | ||
> | ||
{labelText} | ||
</div> | ||
); | ||
}); | ||
return ( | ||
@@ -83,9 +36,4 @@ <div | ||
z-index: 2; | ||
@media (max-width: 650px) { | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
z-index: 4; | ||
user-select: none; | ||
pointer-events: none; | ||
@media (max-width: ${theme.sizes.breakpoints.small}px) { | ||
width: ${theme.sizes.labelWidthSmall}px; | ||
} | ||
@@ -95,11 +43,11 @@ `} | ||
> | ||
{selectionVisibility ? ( | ||
<TimeSelector done={handleCalendarSelection} /> | ||
) : null} | ||
{status.boundsControl ? ( | ||
{selectionVisibility && <TimeSelector done={handleTimeSelection} />} | ||
{status.boundsControl && status.mode !== "free_select" && ( | ||
<TimeSelectorTrigger | ||
handleCalendarSelection={handleCalendarSelection} | ||
handleTimeSelection={handleTimeSelection} | ||
/> | ||
) : null} | ||
)} | ||
{status.mode === "free_select" && <TimeExpander backwards={true} />} | ||
{labelsOutput} | ||
{status.mode === "free_select" && <TimeExpander />} | ||
</div> | ||
@@ -106,0 +54,0 @@ ); |
@@ -66,2 +66,3 @@ import React, { useContext } from "react"; | ||
display: flex; | ||
margin-left: ${theme.sizes.wrapperUnderflow}px; | ||
@media (max-width: 550px) { | ||
@@ -68,0 +69,0 @@ flex-wrap: wrap; |
@@ -27,4 +27,4 @@ import React, { useContext } from "react"; | ||
flex-shrink: 0; | ||
@media (max-width: 650px) { | ||
display: none; | ||
@media (max-width: ${theme.sizes.breakpoints.small}px) { | ||
width: ${theme.sizes.labelWidthSmall}px; | ||
} | ||
@@ -36,2 +36,3 @@ `} | ||
font-size: 20px; | ||
margin-left: ${theme.sizes.wrapperUnderflow}px; | ||
`} | ||
@@ -38,0 +39,0 @@ className={` |
@@ -40,2 +40,3 @@ import React, { useContext } from "react"; | ||
<SlotFreeSelect | ||
key={`slot-free-${slot.start}`} | ||
slot={slot} | ||
@@ -42,0 +43,0 @@ day={day} |
@@ -29,5 +29,3 @@ import React, { useContext, useState } from "react"; | ||
const [timeString] = useState(() => | ||
calculateTimeString(slot, i18n, status.tzid) | ||
); | ||
const [timeString] = useState(calculateTimeString(slot, i18n, status.tzid)); | ||
@@ -34,0 +32,0 @@ const isDragged = drag.dragged.includes(slot.start); |
@@ -56,6 +56,6 @@ import React, { useContext } from "react"; | ||
);` | ||
: ``} | ||
: ""}; | ||
`} | ||
className={`${theme.prefix}__slot-background ${theme.prefix}__slot-background--${slotModifierClass}`} | ||
key={i} | ||
key={`slot_${slot.start}`} | ||
/> | ||
@@ -62,0 +62,0 @@ ); |
@@ -13,32 +13,5 @@ import React, { useContext } from "react"; | ||
import { hours } from "../../helpers/utils"; | ||
import { buttonReset } from "../../styles/utils"; | ||
const timeOptions = [ | ||
"00:00", | ||
"01:00", | ||
"02:00", | ||
"03:00", | ||
"04:00", | ||
"05:00", | ||
"06:00", | ||
"07:00", | ||
"08:00", | ||
"09:00", | ||
"10:00", | ||
"11:00", | ||
"12:00", | ||
"13:00", | ||
"14:00", | ||
"15:00", | ||
"16:00", | ||
"17:00", | ||
"18:00", | ||
"19:00", | ||
"20:00", | ||
"21:00", | ||
"22:00", | ||
"23:00", | ||
"24:00" | ||
]; | ||
const TimeSelector = ({ done }) => { | ||
@@ -66,3 +39,3 @@ const [status, setStatus] = useContext(StatusContext); | ||
const startOptions = timeOptions | ||
const startOptions = hours | ||
.filter(time => { | ||
@@ -83,3 +56,3 @@ const localEnd = limits.end; | ||
const endOptions = timeOptions | ||
const endOptions = hours | ||
.filter(time => { | ||
@@ -86,0 +59,0 @@ const localStart = limits.start; |
@@ -6,3 +6,3 @@ import React, { useContext } from "react"; | ||
const TimeSelectorTrigger = ({ handleCalendarSelection }) => { | ||
const TimeSelectorTrigger = ({ handleTimeSelection }) => { | ||
const [theme, setTheme] = useContext(ThemeContext); | ||
@@ -23,3 +23,3 @@ return ( | ||
`} | ||
onClick={handleCalendarSelection} | ||
onClick={handleTimeSelection} | ||
className={`${theme.prefix}__time-select__trigger`} | ||
@@ -26,0 +26,0 @@ > |
@@ -78,4 +78,4 @@ import React, { useContext, useState, useEffect } from "react"; | ||
const selectedSlots = getSelectedSlots(updatedSlotData); | ||
const queryPeriods = buildPeriodsFromSlots(selectedSlots); | ||
const currentlySelectedSlots = getSelectedSlots(updatedSlotData); | ||
const queryPeriods = buildPeriodsFromSlots(currentlySelectedSlots); | ||
const callbackContent = { | ||
@@ -152,3 +152,5 @@ notification: { | ||
useEffect(() => { | ||
setSelectedSlots({}); | ||
if (status.mode !== "free_select") { | ||
setSelectedSlots({}); | ||
} | ||
}, [limits]); | ||
@@ -264,3 +266,5 @@ | ||
{status.loading ? <Loading /> : null} | ||
{status.preloading ? <Preloading /> : null} | ||
{status.preloading && status.mode !== "free_select" ? ( | ||
<Preloading /> | ||
) : null} | ||
{status.error ? ( | ||
@@ -267,0 +271,0 @@ <Error message={i18n.t("global_error")} theme={theme} /> |
@@ -40,7 +40,4 @@ import React, { useContext, useEffect, useState } from "react"; | ||
const labelColumnWidth = gridWrapper.current.children[0].clientWidth; | ||
const availableSpaceForGrid = elementWidth - labelColumnWidth; | ||
// Account for small-screen layout | ||
const availableSpaceForGrid = | ||
size.width > 650 ? elementWidth - labelColumnWidth : elementWidth; | ||
const columnCount = 7; | ||
@@ -47,0 +44,0 @@ if (availableSpaceForGrid) { |
@@ -230,3 +230,3 @@ import * as mocks from "./mocks"; | ||
export const getAvailabilityRules = ( | ||
export const getAvailabilityRules = ({ | ||
token, | ||
@@ -236,5 +236,6 @@ api_domain, | ||
element = "rules", | ||
mock = false | ||
) => { | ||
if (mock) return mocks.availability_rules; | ||
mock = false, | ||
tzid = false | ||
}) => { | ||
if (mock) return mocks.availability_rules(tzid); | ||
@@ -262,3 +263,3 @@ const url = new URL( | ||
export const setAvailabilityRules = ( | ||
export const setAvailabilityRules = ({ | ||
token, | ||
@@ -268,5 +269,6 @@ api_domain, | ||
element = "rules", | ||
mock = false | ||
) => { | ||
if (mock) return mocks.availability_rules; | ||
mock = false, | ||
tzid = false | ||
}) => { | ||
if (mock) return mocks.availability_rules(tzid); | ||
@@ -273,0 +275,0 @@ return fetch(`${api_domain}/v1/availability_rules?et=${token}`, { |
@@ -1,7 +0,6 @@ | ||
import moment from "moment-timezone"; | ||
import { | ||
parseConnectionDomains, | ||
parseTarget, | ||
parseTimzone, | ||
parseToken, | ||
parseTarget, | ||
parseConnectionDomains, | ||
parseTranslations | ||
@@ -73,6 +72,3 @@ } from "./init"; | ||
if (typeof options.tzid === "undefined") { | ||
const sniffedTimezone = moment.tz.guess(); | ||
options.tzid = sniffedTimezone; | ||
} | ||
const tzid = parseTimzone(options.tzid, "availability-rules", log); | ||
@@ -92,2 +88,3 @@ const domains = parseConnectionDomains( | ||
...options, | ||
...tzid, | ||
target, | ||
@@ -94,0 +91,0 @@ token, |
import moment from "moment-timezone"; | ||
import { | ||
parseConnectionDomains, | ||
parseInterval, | ||
parseQuery, | ||
parseTarget, | ||
parseTimzone, | ||
parseToken, | ||
parseTarget, | ||
parseQuery, | ||
parseConnectionDomains, | ||
parseTranslations | ||
@@ -50,9 +51,4 @@ } from "./init"; | ||
if (typeof options.tzid === "undefined") { | ||
const sniffedTimezone = moment.tz.guess(); | ||
options.tzid = sniffedTimezone; | ||
options.customtzid = false; | ||
} else { | ||
options.customtzid = true; | ||
} | ||
const tzid = parseTimzone(options.tzid, "availability-viewer", log); | ||
options = { ...options, ...tzid }; | ||
@@ -81,3 +77,3 @@ const mode = | ||
query.required_duration.minutes = interval; | ||
const now = moment.utc().endOf("hour"); | ||
const now = moment.utc().startOf("hour").add(1, "hour"); | ||
// Adding 34 days to ensure that the resulting query stays within the requiered bounds defined in | ||
@@ -84,0 +80,0 @@ // https://docs.cronofy.com/developers/api/scheduling/availability/#param-participants.members.available_periods.end |
import merge from "deepmerge"; | ||
import { translations } from "./translations"; | ||
import moment from "moment-timezone"; | ||
@@ -138,1 +139,19 @@ export const parseConnectionDomains = ( | ||
}; | ||
export const parseTimzone = (option, elementSlug = false, log) => { | ||
const docsHash = elementSlug ? `${elementSlug}/#param-tzid` : ""; | ||
const isValidTzid = moment.tz.zone(option); | ||
const sniffedTimezone = !isValidTzid ? moment.tz.guess() : ""; | ||
if (typeof option !== "undefined" && !isValidTzid) { | ||
log.warn( | ||
`The provided TZID of ${option} is not valid. Using ${sniffedTimezone} instead. Full details of valid TZIDs can be found on the Cronofy Elements documention page: https://docs.cronofy.com/developers/ui-elements/${docsHash}` | ||
); | ||
} | ||
return { | ||
tzid: !isValidTzid ? sniffedTimezone : option, | ||
customtzid: typeof option !== "undefined" | ||
}; | ||
}; |
@@ -1,7 +0,7 @@ | ||
import moment from "moment-timezone"; | ||
import { | ||
parseConnectionDomains, | ||
parseQuery, | ||
parseTarget, | ||
parseTimzone, | ||
parseToken, | ||
parseTarget, | ||
parseQuery, | ||
parseConnectionDomains, | ||
parseTranslations | ||
@@ -34,9 +34,3 @@ } from "./init"; | ||
if (typeof options.tzid === "undefined") { | ||
const sniffedTimezone = moment.tz.guess(); | ||
options.tzid = sniffedTimezone; | ||
options.customtzid = false; | ||
} else { | ||
options.customtzid = true; | ||
} | ||
const tzid = parseTimzone(options.tzid, "slot-picker", log); | ||
@@ -61,2 +55,3 @@ const domains = parseConnectionDomains( | ||
...options, | ||
...tzid, | ||
target, | ||
@@ -63,0 +58,0 @@ token, |
@@ -273,11 +273,11 @@ import moment from "moment-timezone"; | ||
export const events = new Promise(function(resolve, reject) { | ||
export const events = new Promise(function (resolve, reject) { | ||
resolve(staticEvents); | ||
}); | ||
export const userinfo = new Promise(function(resolve, reject) { | ||
export const userinfo = new Promise(function (resolve, reject) { | ||
resolve(staticUserinfo); | ||
}); | ||
export const eventsWithUserinfo = new Promise(function(resolve, reject) { | ||
export const eventsWithUserinfo = new Promise(function (resolve, reject) { | ||
resolve({ | ||
@@ -289,3 +289,3 @@ events: staticEvents, | ||
export const availability = new Promise(function(resolve, reject) { | ||
export const availability = new Promise(function (resolve, reject) { | ||
const utcOffset = moment().utcOffset(); | ||
@@ -296,5 +296,3 @@ const invertedOffset = | ||
const today = moment() | ||
.add(1, "day") | ||
.seconds(0); | ||
const today = moment().add(1, "day").seconds(0); | ||
const startOfWeek = today | ||
@@ -304,3 +302,3 @@ .startOf("isoWeek") | ||
.add(7, "days"); | ||
const offsetTime = function(days, time) { | ||
const offsetTime = function (days, time) { | ||
const timeString = `${startOfWeek | ||
@@ -501,3 +499,3 @@ .clone() | ||
export const availabilitySlots = new Promise(function(resolve, reject) { | ||
export const availabilitySlots = new Promise(function (resolve, reject) { | ||
const utcOffset = moment().utcOffset(); | ||
@@ -508,5 +506,3 @@ const invertedOffset = | ||
const today = moment() | ||
.add(1, "day") | ||
.seconds(0); | ||
const today = moment().add(1, "day").seconds(0); | ||
const startOfWeek = today | ||
@@ -516,3 +512,3 @@ .startOf("isoWeek") | ||
.add(7, "days"); | ||
const offsetTime = function(days, time) { | ||
const offsetTime = function (days, time) { | ||
const timeString = `${startOfWeek | ||
@@ -623,5 +619,3 @@ .clone() | ||
const today = moment() | ||
.add(1, "day") | ||
.seconds(0); | ||
const today = moment().add(1, "day").seconds(0); | ||
const startOfWeek = today | ||
@@ -631,3 +625,3 @@ .startOf("isoWeek") | ||
.add(7, "days"); | ||
const offsetTime = function(days, time) { | ||
const offsetTime = function (days, time) { | ||
const timeString = `${startOfWeek | ||
@@ -809,15 +803,16 @@ .clone() | ||
export const availability_rules = new Promise(function(resolve, reject) { | ||
const sniffedTimezone = moment.tz.guess(); | ||
resolve({ | ||
availability_rule: { | ||
availability_rule_id: "default", | ||
tzid: sniffedTimezone, | ||
calendar_ids: ["A_CALENDAR_ID_0"], | ||
weekly_periods: default_availability_rules | ||
} | ||
export const availability_rules = tzid => | ||
new Promise(function (resolve, reject) { | ||
const timezone = tzid || moment.tz.guess(); | ||
resolve({ | ||
availability_rule: { | ||
availability_rule_id: "default", | ||
tzid: timezone, | ||
calendar_ids: ["A_CALENDAR_ID_0"], | ||
weekly_periods: default_availability_rules | ||
} | ||
}); | ||
}); | ||
}); | ||
export const revokeProfile = new Promise(function(resolve, reject) { | ||
export const revokeProfile = new Promise(function (resolve, reject) { | ||
resolve({ | ||
@@ -824,0 +819,0 @@ status: 202 |
@@ -285,4 +285,29 @@ import moment from "moment-timezone"; | ||
export const checkWeekdaysSlotAvailabilityFreeSelect = ( | ||
weekdaysEmpties, | ||
availablePeriods | ||
) => { | ||
return weekdaysEmpties.map(day => ({ | ||
...day, | ||
slots: day.slots.map(slot => { | ||
const withinPeriod = Object.keys(availablePeriods).map( | ||
periodKey => { | ||
const period = availablePeriods[periodKey]; | ||
return slot.start >= period.start && slot.end <= period.end; | ||
} | ||
); | ||
const result = withinPeriod.reduce((bool, acc) => { | ||
if (bool) { | ||
return true; | ||
} else { | ||
return acc; | ||
} | ||
}, false); | ||
return { ...slot, visiblyAvailable: result }; | ||
}) | ||
})); | ||
}; | ||
export const generatePageSlots = ( | ||
{ availablePeriods, limits, pages, tzid, unrestricted }, | ||
{ availablePeriods, limits, pages, tzid, unrestricted, freeSelect = false }, | ||
getEmpties = createEmptySlotsForPeriod, | ||
@@ -304,2 +329,14 @@ buildPeriod = buildDayPeriod | ||
if (freeSelect) { | ||
const allSlots = checkWeekdaysSlotAvailabilityFreeSelect( | ||
weekdaysEmpties, | ||
availablePeriods | ||
); | ||
return { | ||
pages, | ||
slots: allSlots | ||
}; | ||
} | ||
const allSlots = checkWeekdaysSlotAvailability( | ||
@@ -666,26 +703,29 @@ weekdaysEmpties, | ||
export const checkSelectedState = (newSlots, oldSlots) => { | ||
// Slots are grouped by day. | ||
const mergedSlots = newSlots.map(day => { | ||
const match = oldSlots.find(d => d.day === day.day); | ||
if (match && day.slots.length === match.slots.length) { | ||
// If there is a match (and they have the same number of slots) | ||
// then it's safe to assume that the slots match 1:1 and that | ||
// `day.slots[n]` is the same slot as `match.slots[n]` | ||
const updated = day.slots.map((slot, i) => { | ||
const old = match.slots[i]; | ||
if (old.selected) { | ||
// This slot should be "selected" | ||
return { | ||
...slot, | ||
selected: true | ||
}; | ||
} | ||
// The slot is not "selected", and can be returned unchanged. | ||
return slot; | ||
}); | ||
return { ...day, slots: updated }; | ||
} | ||
return day; | ||
}); | ||
let selectedTimes = []; | ||
oldSlots.map(day => | ||
day.slots.map(slot => { | ||
if (slot.selected) { | ||
selectedTimes.push(slot.start); | ||
} | ||
}) | ||
); | ||
const mergedSlots = newSlots.map(day => ({ | ||
...day, | ||
slots: day.slots.map(slot => { | ||
if (selectedTimes.includes(slot.start)) { | ||
return { | ||
...slot, | ||
selected: true | ||
}; | ||
} | ||
return slot; | ||
}) | ||
})); | ||
return mergedSlots; | ||
}; | ||
export const condenseTimeLabel = label => | ||
label | ||
.replace(/[^0-9][0-9]{2} ?/g, "") | ||
.replace(/m/i, "") | ||
.replace(" ", ""); |
@@ -40,1 +40,29 @@ import { compose } from "./functional"; | ||
export const filterObject = (key, { [key]: _, ...rest }) => rest; | ||
export const hours = [ | ||
"00:00", | ||
"01:00", | ||
"02:00", | ||
"03:00", | ||
"04:00", | ||
"05:00", | ||
"06:00", | ||
"07:00", | ||
"08:00", | ||
"09:00", | ||
"10:00", | ||
"11:00", | ||
"12:00", | ||
"13:00", | ||
"14:00", | ||
"15:00", | ||
"16:00", | ||
"17:00", | ||
"18:00", | ||
"19:00", | ||
"20:00", | ||
"21:00", | ||
"22:00", | ||
"23:00", | ||
"24:00" | ||
]; |
{ | ||
"availability_viewer": { | ||
"available": "Available", | ||
"backward": "Backward", | ||
"booked": "Booked", | ||
@@ -8,2 +9,3 @@ "busy": "Busy", | ||
"end": "End", | ||
"forward": "Forward", | ||
"free": "Free", | ||
@@ -10,0 +12,0 @@ "no_slots_found": "No slots found", |
@@ -512,6 +512,7 @@ // import fetchMock from "fetch-mock"; | ||
const res = await connections.getAvailabilityRules( | ||
...exampleOptions, | ||
"availability_rule_id" | ||
); | ||
const res = await connections.getAvailabilityRules({ | ||
token: exampleOptions[0], | ||
api_domain: exampleOptions[1], | ||
availability_rule_id: "availability_rule_id" | ||
}); | ||
@@ -527,3 +528,7 @@ expect(res).toEqual(mockBody); | ||
await connections | ||
.getAvailabilityRules(...exampleOptions, "availability_rule_id") | ||
.getAvailabilityRules({ | ||
token: exampleOptions[0], | ||
api_domain: exampleOptions[1], | ||
availability_rule_id: "availability_rule_id" | ||
}) | ||
.catch(err => { | ||
@@ -538,6 +543,7 @@ expect(typeof err.message).toEqual("string"); | ||
const res = await connections.getAvailabilityRules( | ||
...exampleOptions, | ||
"availability_rule_id" | ||
); | ||
const res = await connections.getAvailabilityRules({ | ||
token: exampleOptions[0], | ||
api_domain: exampleOptions[1], | ||
availability_rule_id: "availability_rule_id" | ||
}); | ||
@@ -544,0 +550,0 @@ expect(res.type).toEqual(404); |
@@ -235,3 +235,3 @@ import moment from "moment-timezone"; | ||
target_id: "TARGET", | ||
tzid: "CUSTOM_TIME_ZONE" | ||
tzid: sniffedTimezone | ||
}; | ||
@@ -259,3 +259,3 @@ const expectedOutput = { | ||
token: "TOKEN", | ||
tzid: "CUSTOM_TIME_ZONE" | ||
tzid: sniffedTimezone | ||
}; | ||
@@ -280,3 +280,3 @@ const result = parseAvailabilityViewerOptions(input); | ||
target_id: "TARGET", | ||
tzid: "CUSTOM_TIME_ZONE", | ||
tzid: sniffedTimezone, | ||
config: { start_time: "01:00", end_time: "02:00" } | ||
@@ -560,3 +560,3 @@ }; | ||
element_token: "TOKEN", | ||
tzid: "CUSTOM_TIME_ZONE" | ||
tzid: sniffedTimezone | ||
}; | ||
@@ -566,5 +566,27 @@ const result = parseAvailabilityViewerOptions(input); | ||
expect(result.customtzid).toEqual(true); | ||
expect(result.tzid).toEqual("CUSTOM_TIME_ZONE"); | ||
expect(result.tzid).toEqual(sniffedTimezone); | ||
}); | ||
it("correctly falls back when given an invalid tzid option", () => { | ||
const input = { | ||
data_center: "DATA_CENTER", | ||
availability_query: { | ||
query_periods: "TEST", | ||
required_duration: "TEST" | ||
}, | ||
config: { | ||
start_time: "01:00", | ||
end_time: "02:00" | ||
}, | ||
target_id: "TARGET", | ||
element_token: "TOKEN", | ||
tzid: "A_NON_IANA_TZID" | ||
}; | ||
const result = parseAvailabilityViewerOptions(input); | ||
expect(result.customtzid).toEqual(true); | ||
expect(result.tzid).toEqual(sniffedTimezone); | ||
expect(console.warn).toHaveBeenCalledTimes(1); | ||
}); | ||
it("correctly adds a fallback tzid option", () => { | ||
@@ -592,2 +614,4 @@ const input = { | ||
describe("Parsing AvailabilityRules options", () => { | ||
const sniffedTimezone = moment.tz.guess(); | ||
it("works when all options are declared", () => { | ||
@@ -603,3 +627,3 @@ const input = { | ||
availability_rule_id: "RULE_ID", | ||
tzid: "TZID" | ||
tzid: sniffedTimezone | ||
}; | ||
@@ -617,3 +641,3 @@ const expectedOutput = { | ||
token: "TOKEN", | ||
tzid: "TZID" | ||
tzid: sniffedTimezone | ||
}; | ||
@@ -639,3 +663,3 @@ const result = parseAvailabilityRulesOptions(input); | ||
target_id: "TARGET", | ||
tzid: "TZID" | ||
tzid: sniffedTimezone | ||
}; | ||
@@ -664,3 +688,3 @@ parseAvailabilityRulesOptions(input); | ||
token: false, | ||
tzid: "TZID" | ||
tzid: sniffedTimezone | ||
}; | ||
@@ -670,3 +694,3 @@ const result = parseAvailabilityRulesOptions({ | ||
availability_rule_id: "RULE_ID", | ||
tzid: "TZID" | ||
tzid: sniffedTimezone | ||
}); | ||
@@ -690,3 +714,3 @@ expect(result.demo).toEqual(expectedOutput.demo); | ||
token: "TOKEN", | ||
tzid: "TZID" | ||
tzid: sniffedTimezone | ||
}; | ||
@@ -696,3 +720,3 @@ const result = parseAvailabilityRulesOptions({ | ||
availability_rule_id: "RULE_ID", | ||
tzid: "TZID" | ||
tzid: sniffedTimezone | ||
}); | ||
@@ -715,3 +739,3 @@ expect(result.target).toEqual(expectedOutput.target); | ||
token: "TOKEN", | ||
tzid: "TZID" | ||
tzid: sniffedTimezone | ||
}; | ||
@@ -722,3 +746,3 @@ const result = parseAvailabilityRulesOptions({ | ||
target_id: "TARGET", | ||
tzid: "TZID" | ||
tzid: sniffedTimezone | ||
}); | ||
@@ -742,3 +766,3 @@ expect(result.domains).toEqual(expectedOutput.domains); | ||
token: "TOKEN", | ||
tzid: "TZID" | ||
tzid: sniffedTimezone | ||
}; | ||
@@ -750,3 +774,3 @@ const result = parseAvailabilityRulesOptions({ | ||
target_id: "TARGET", | ||
tzid: "TZID" | ||
tzid: sniffedTimezone | ||
}); | ||
@@ -753,0 +777,0 @@ expect(result.domains).toEqual(expectedOutput.domains); |
@@ -1064,2 +1064,25 @@ import * as utils from "../src/js/helpers/utils.AvailabilityViewer"; | ||
}); | ||
// condenseTimeLabel | ||
it("correctly truncates time string based on locale", () => { | ||
const enTimes = ["09:00", "10:00", "13:00", "23:00"]; | ||
const usTimes = ["9:00 am", "10:00 am", "1:00 pm", "11 pm"]; | ||
const weirds = ["9:00am", "1:00 PM", "11pm", "02pm", "02 pm"]; | ||
expect(utils.condenseTimeLabel(enTimes[0])).toEqual("09"); | ||
expect(utils.condenseTimeLabel(enTimes[1])).toEqual("10"); | ||
expect(utils.condenseTimeLabel(enTimes[2])).toEqual("13"); | ||
expect(utils.condenseTimeLabel(enTimes[3])).toEqual("23"); | ||
expect(utils.condenseTimeLabel(usTimes[0])).toEqual("9a"); | ||
expect(utils.condenseTimeLabel(usTimes[1])).toEqual("10a"); | ||
expect(utils.condenseTimeLabel(usTimes[2])).toEqual("1p"); | ||
expect(utils.condenseTimeLabel(usTimes[3])).toEqual("11p"); | ||
expect(utils.condenseTimeLabel(weirds[0])).toEqual("9a"); | ||
expect(utils.condenseTimeLabel(weirds[1])).toEqual("1P"); | ||
expect(utils.condenseTimeLabel(weirds[2])).toEqual("11p"); | ||
expect(utils.condenseTimeLabel(weirds[3])).toEqual("02p"); | ||
expect(utils.condenseTimeLabel(weirds[4])).toEqual("02p"); | ||
}); | ||
}); |
@@ -130,3 +130,3 @@ const webpack = require("webpack"); | ||
new BundleAnalyzerPlugin({ | ||
analyzerMode: argv.mode === "development" ? "server" : "disabled", // server | static | disabled | ||
analyzerMode: argv.analyse ? "server" : "disabled", // server | static | disabled | ||
analyzerPort: 8181 | ||
@@ -133,0 +133,0 @@ }), |
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
2610693
230
24349