@open-tender/utils
Version:
A library of utils for use with Open Tender applications that utilize our cloud-based Order API.
604 lines (603 loc) • 28.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeEstimatedTime = exports.makeRequestedAtStr = exports.makeRequestedIso = exports.makeReadableDateStrFromIso = exports.isoToDateStrMinutes = exports.dateStrMinutesToIso = exports.formatTimeStr = exports.formatDateStr = exports.formatDate = exports.replaceAmPm = exports.dateStrToZonedWeekday = exports.dateStrToZonedDate = exports.dateStrToDate = exports.currentLocalDateStr = exports.currentLocalDate = exports.dateToZonedIso = exports.dateToZonedDateStr = exports.adjustZonedIso = exports.adjustIso = exports.dateToIso = exports.cleanISOString = exports.isoToDateStr = exports.isoToDate = exports.tomorrowDate = exports.todayDate = exports.makeLocalDateStr = exports.zonedTimeToDateStr = exports.zonedTimeToDate = exports.makeLocalDate = exports.getUserTimezone = exports.fmtDate = exports.parseIsoToDate = exports.weekdayAndTimeToDate = exports.dateForWeekday = exports.timeLeft = exports.secondsToTime = exports.secondsLeft = exports.minutesLeft = exports.makeWeekday = exports.weekdayOptions = exports.weekdaysLower = exports.weekdaysUpper = exports.weekdays = exports.timezoneMap = exports.HUMAN_DATETIME = exports.HUMAN_TIME = exports.HUMAN_DATE = exports.DATETIME = exports.TIME = exports.DATE = void 0;
exports.makeOrderWindow = exports.makeCartDateStr = exports.formatTimeList = exports.makeIntervals = exports.getLastInterval = exports.makeGroupOrderTimeStr = exports.formatTime = exports.makeGroupOrderTime = exports.getFirstTime = exports.adjustRequestedAt = exports.getNextInterval = exports.makeFirstTimes = exports.makeFirstRequestedAt = exports.makeFirstTime = exports.findOrderTime = exports.makeOrderTimes = exports.makeTimes = exports.makeDates = exports.getNextIntervalMinutes = exports.getMinutesfromDate = exports.minutesToDates = exports.time24ToDateStr = exports.time24ToDate = exports.minutesToDate = exports.setTimeForDate = exports.time24ToMinutes = exports.makeOppositeTimes = void 0;
const date_fns_1 = require("date-fns");
const date_fns_tz_1 = require("date-fns-tz");
/* CONSTANTS */
exports.DATE = 'yyyy-MM-dd';
exports.TIME = 'h:mma';
exports.DATETIME = 'yyyy-MM-dd h:mma';
exports.HUMAN_DATE = 'MMM d, yyyy';
exports.HUMAN_TIME = 'h:mma';
exports.HUMAN_DATETIME = 'MMM d, h:mma';
exports.timezoneMap = {
'US/Eastern': 'America/New_York',
'US/Central': 'America/Chicago',
'US/Mountain': 'America/Denver',
'US/Pacific': 'America/Los_Angeles'
};
exports.weekdays = [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday'
];
exports.weekdaysUpper = exports.weekdays.map(weekday => weekday.toUpperCase());
exports.weekdaysLower = exports.weekdays.map(weekday => weekday.toLowerCase());
exports.weekdayOptions = exports.weekdays.map(weekday => ({
value: weekday.toUpperCase(),
name: weekday
}));
const makeWeekday = (date = new Date()) => {
return (0, date_fns_tz_1.format)(date, 'EEEE').toUpperCase();
};
exports.makeWeekday = makeWeekday;
const minutesLeft = (start, end) => {
return Math.max((0, date_fns_1.differenceInMinutes)(start, end), 0);
};
exports.minutesLeft = minutesLeft;
const secondsLeft = (start, end) => {
return Math.max((0, date_fns_1.differenceInSeconds)(start, end), 0);
};
exports.secondsLeft = secondsLeft;
const secondsToTime = (seconds) => {
const mins = Math.floor(seconds / 60);
const secs = `${seconds % 60}`.padStart(2, '0');
return `${mins}:${secs}`;
};
exports.secondsToTime = secondsToTime;
const timeLeft = (start, end) => {
const seconds = (0, exports.secondsLeft)(start, end);
return (0, exports.secondsToTime)(seconds);
};
exports.timeLeft = timeLeft;
const dateForWeekday = (weekday) => {
const currentWeekday = (0, exports.makeWeekday)();
const currentIndex = exports.weekdaysUpper.findIndex(i => i === currentWeekday);
const index = exports.weekdaysUpper.findIndex(i => i === weekday.toUpperCase());
const offset = index - currentIndex + (index >= currentIndex ? 0 : 7);
return (0, date_fns_1.add)(new Date(), { days: offset });
};
exports.dateForWeekday = dateForWeekday;
const weekdayAndTimeToDate = (weekday, timeStr) => {
const date = (0, exports.dateForWeekday)(weekday);
const [hours, minutes] = timeStr.split(':').map(i => parseInt(i));
return (0, exports.setTimeForDate)(date, hours, minutes);
};
exports.weekdayAndTimeToDate = weekdayAndTimeToDate;
/* HELPERS */
const parseIsoToDate = (iso) => (0, date_fns_1.parseISO)(iso);
exports.parseIsoToDate = parseIsoToDate;
const fmtDate = (date, fmt) => {
return (0, date_fns_tz_1.format)(date, fmt);
};
exports.fmtDate = fmtDate;
// https://stackoverflow.com/questions/54555491/how-to-guess-users-timezone-using-date-fns-in-a-vuejs-app
const getUserTimezone = () => {
try {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
}
catch (err) {
return 'America/New_York';
}
};
exports.getUserTimezone = getUserTimezone;
const makeLocalDate = (dateStr) => {
const tz = (0, exports.getUserTimezone)();
return (0, date_fns_tz_1.toDate)(dateStr, { timeZone: tz });
};
exports.makeLocalDate = makeLocalDate;
const zonedTimeToDate = (str, timezone) => {
const tz = exports.timezoneMap[timezone];
return (0, date_fns_tz_1.toDate)(str.split('.')[0], { timeZone: tz });
};
exports.zonedTimeToDate = zonedTimeToDate;
const zonedTimeToDateStr = (str, timezone, fmt = exports.DATE) => {
const date = (0, exports.zonedTimeToDate)(str, timezone);
return (0, date_fns_tz_1.format)(date, fmt);
};
exports.zonedTimeToDateStr = zonedTimeToDateStr;
// returns a date string in a user's local time
const makeLocalDateStr = (date, days = 0, fmt = exports.DATE) => {
return (0, date_fns_tz_1.format)((0, date_fns_1.add)(date || new Date(), { days: days }), fmt);
};
exports.makeLocalDateStr = makeLocalDateStr;
const todayDate = () => (0, exports.makeLocalDateStr)();
exports.todayDate = todayDate;
const tomorrowDate = () => (0, exports.makeLocalDateStr)(null, 1);
exports.tomorrowDate = tomorrowDate;
const isoToDate = (iso, tz) => {
return tz ? (0, date_fns_tz_1.utcToZonedTime)((0, date_fns_1.parseISO)(iso), tz) : (0, date_fns_1.parseISO)(iso);
};
exports.isoToDate = isoToDate;
const isoToDateStr = (iso, tz, fmt = exports.DATETIME) => {
return (0, date_fns_tz_1.format)((0, exports.isoToDate)(iso, tz), fmt);
};
exports.isoToDateStr = isoToDateStr;
const cleanISOString = (date) => {
return (date.toISOString().split('.')[0] + 'Z');
};
exports.cleanISOString = cleanISOString;
const dateToIso = (date, tz) => {
return (0, exports.cleanISOString)((0, date_fns_tz_1.zonedTimeToUtc)(date, tz));
};
exports.dateToIso = dateToIso;
const adjustIso = (iso, tz, adjustment) => {
const date = (0, exports.isoToDate)(iso, tz);
return (0, exports.dateToIso)((0, date_fns_1.add)(date, adjustment), tz);
};
exports.adjustIso = adjustIso;
const adjustZonedIso = (zonedIso, tz, adjustment) => {
const adjusted = (0, date_fns_1.add)((0, date_fns_tz_1.toDate)(zonedIso), adjustment);
const zoned = (0, date_fns_tz_1.utcToZonedTime)(adjusted, tz);
const dateStr = (0, date_fns_tz_1.format)(zoned, "yyyy-MM-dd'T'HH:mm:ssXXX", { timeZone: tz });
return dateStr;
};
exports.adjustZonedIso = adjustZonedIso;
const dateToZonedDateStr = (date, tz, fmt = "yyyy-MM-dd'T'HH:mm:ssXXX", days = 0) => {
const adjustedDate = (0, date_fns_1.add)(date, { days: days });
const zoned = (0, date_fns_tz_1.utcToZonedTime)(adjustedDate, tz);
return (0, date_fns_tz_1.format)(zoned, fmt, { timeZone: tz });
};
exports.dateToZonedDateStr = dateToZonedDateStr;
const dateToZonedIso = (date, tz) => {
const zoned = (0, date_fns_tz_1.utcToZonedTime)(date, tz);
return (0, date_fns_tz_1.format)(zoned, "yyyy-MM-dd'T'HH:mm:ssXXX", { timeZone: tz });
};
exports.dateToZonedIso = dateToZonedIso;
const currentLocalDate = (tz) => {
const date = new Date();
return (0, exports.isoToDate)(date.toISOString(), tz);
};
exports.currentLocalDate = currentLocalDate;
const currentLocalDateStr = (tz, fmt = exports.DATE) => {
const date = new Date();
return (0, date_fns_tz_1.format)((0, exports.isoToDate)(date.toISOString(), tz), fmt);
};
exports.currentLocalDateStr = currentLocalDateStr;
const dateStrToDate = (str) => (0, date_fns_tz_1.toDate)(str);
exports.dateStrToDate = dateStrToDate;
const dateStrToZonedDate = (str, tz) => {
return (0, date_fns_tz_1.toDate)(str, { timeZone: tz });
};
exports.dateStrToZonedDate = dateStrToZonedDate;
const dateStrToZonedWeekday = (str) => {
return (0, exports.makeWeekday)((0, date_fns_tz_1.toDate)(str));
};
exports.dateStrToZonedWeekday = dateStrToZonedWeekday;
const replaceAmPm = (str) => str.replace('AM', 'am').replace('PM', 'pm');
exports.replaceAmPm = replaceAmPm;
const formatDate = (date, fmt = exports.HUMAN_DATETIME, amPm = true) => {
const str = (0, date_fns_tz_1.format)(date, fmt);
return amPm ? (0, exports.replaceAmPm)(str) : str;
};
exports.formatDate = formatDate;
const formatDateStr = (str, fmt = exports.HUMAN_DATE) => {
return str ? (0, date_fns_tz_1.format)((0, date_fns_tz_1.toDate)(str), fmt) : null;
};
exports.formatDateStr = formatDateStr;
const formatTimeStr = (str) => {
const clean = str.replace(/\s/g, '').toLowerCase();
const parts = clean.split('-');
if (parts.length === 1)
return clean;
const [part1, part2] = parts;
const end1 = part1.substr(part1.length - 2);
const end2 = part2.substr(part1.length - 2);
const newPart1 = ['am', 'pm'].includes(end1) && end1 === end2
? part1.slice(0, part1.length - 2)
: part1;
return [newPart1, part2].join('-');
};
exports.formatTimeStr = formatTimeStr;
const dateStrMinutesToIso = (dateStr, minutes, tz) => {
const hours = Math.floor(minutes / 60)
.toString()
.padStart(2, '0');
const mins = (minutes % 60).toString().padStart(2, '0');
const timeStr = `${hours}:${mins}:00`;
const dateTimeStr = `${dateStr} ${timeStr}`;
const dateUtc = (0, date_fns_tz_1.zonedTimeToUtc)(dateTimeStr, tz);
return (0, exports.cleanISOString)(dateUtc);
};
exports.dateStrMinutesToIso = dateStrMinutesToIso;
const isoToDateStrMinutes = (iso, tz) => {
const dateObj = (0, exports.isoToDate)(iso, tz);
const minutes = (0, exports.getMinutesfromDate)(dateObj);
const date = (0, date_fns_tz_1.format)(dateObj, exports.DATE);
return { date, minutes };
};
exports.isoToDateStrMinutes = isoToDateStrMinutes;
const makeReadableDateStrFromIso = (iso, tz, verbose = false, withTime = true) => {
if (!iso || iso.toLowerCase() === 'asap')
return 'ASAP';
const date = (0, date_fns_tz_1.utcToZonedTime)((0, date_fns_1.parseISO)(iso), tz);
const timeString = (0, date_fns_tz_1.format)(date, exports.TIME).toLowerCase();
const dateString = (0, exports.makeLocalDateStr)(date);
if (dateString === (0, exports.todayDate)()) {
if (!withTime)
return 'Today';
return verbose ? `Today @ ${timeString}` : timeString;
}
else if (dateString === (0, exports.tomorrowDate)()) {
return `${verbose ? 'Tomorrow' : 'Tmrw'} ${withTime ? `@ ${timeString}` : ''}`;
}
else {
return `${verbose ? (0, date_fns_tz_1.format)(date, 'EEE, MMM d') : (0, date_fns_tz_1.format)(date, 'M/d')} ${withTime ? `@ ${timeString}` : ''}`;
}
};
exports.makeReadableDateStrFromIso = makeReadableDateStrFromIso;
const makeRequestedIso = (requestedAt) => {
return !requestedAt || requestedAt === 'asap'
? (0, exports.cleanISOString)(new Date())
: requestedAt;
};
exports.makeRequestedIso = makeRequestedIso;
const makeRequestedAtStr = (requestedAt, tz, verbose = false) => {
if (!requestedAt || requestedAt.toLowerCase() === 'asap')
return 'ASAP';
return (0, exports.makeReadableDateStrFromIso)(requestedAt, tz, verbose);
};
exports.makeRequestedAtStr = makeRequestedAtStr;
const makeEstimatedTime = (requestedAt, revenueCenter, serviceType, verbose = false) => {
var _a, _b;
if (requestedAt !== 'asap' || !serviceType || !revenueCenter)
return null;
const settings = revenueCenter;
const { first_times } = settings;
if (!first_times)
return null;
const st = serviceType === 'WALKIN' ? 'PICKUP' : serviceType;
const firstTime = first_times[st];
if ((firstTime === null || firstTime === void 0 ? void 0 : firstTime.date) === (0, exports.todayDate)()) {
return `around ${firstTime.time}`;
}
else if ((firstTime === null || firstTime === void 0 ? void 0 : firstTime.date) === (0, exports.tomorrowDate)()) {
return `tomorrow @ ${(0, exports.formatTimeStr)(firstTime === null || firstTime === void 0 ? void 0 : firstTime.time)}`;
}
else {
const tz = exports.timezoneMap[(_a = revenueCenter.timezone) !== null && _a !== void 0 ? _a : 'US/Eastern'];
const date = (0, date_fns_tz_1.toDate)((_b = firstTime === null || firstTime === void 0 ? void 0 : firstTime.date) !== null && _b !== void 0 ? _b : new Date(), { timeZone: tz });
return `${verbose ? (0, date_fns_tz_1.format)(date, 'EEEE, MMMM d') : (0, date_fns_tz_1.format)(date, 'M/d')} @ ${firstTime === null || firstTime === void 0 ? void 0 : firstTime.time}`;
}
};
exports.makeEstimatedTime = makeEstimatedTime;
function* range(start, end, step) {
for (let i = start; i <= end; i += step) {
yield i;
}
}
const makeOppositeTimes = (times, interval, min = 0, max = 1440) => {
return [...range(min, max - interval, interval)].filter(i => !times.includes(i));
};
exports.makeOppositeTimes = makeOppositeTimes;
const time24ToMinutes = (str) => {
const [hours, minutes] = str.split(':');
return parseInt(hours) * 60 + parseInt(minutes);
};
exports.time24ToMinutes = time24ToMinutes;
const setTimeForDate = (date, hours, minutes, seconds = 0) => {
date.setHours(hours);
date.setMinutes(minutes);
date.setSeconds(seconds);
date.setMilliseconds(0);
return date;
};
exports.setTimeForDate = setTimeForDate;
const minutesToDate = (minutes, date) => {
const hours = Math.floor(minutes / 60);
const mins = minutes % 60;
const dateCloned = date ? new Date(date.getTime()) : new Date();
return (0, exports.setTimeForDate)(dateCloned, hours, mins);
};
exports.minutesToDate = minutesToDate;
const time24ToDate = (str) => {
const minutes = (0, exports.time24ToMinutes)(str);
return (0, exports.minutesToDate)(minutes);
};
exports.time24ToDate = time24ToDate;
const time24ToDateStr = (str, fmt = exports.TIME) => {
const minutes = (0, exports.time24ToMinutes)(str);
return (0, date_fns_tz_1.format)((0, exports.minutesToDate)(minutes), fmt).replace(':00', '').toLowerCase();
};
exports.time24ToDateStr = time24ToDateStr;
const minutesToDates = (minutes, date) => {
return minutes.map(minute => {
return (0, exports.minutesToDate)(minute, date);
});
};
exports.minutesToDates = minutesToDates;
const getMinutesfromDate = (date) => {
return date.getHours() * 60 + date.getMinutes();
};
exports.getMinutesfromDate = getMinutesfromDate;
const getNextIntervalMinutes = (minutes, interval) => {
const hours = Math.floor(minutes / 60);
const mins = minutes % 60;
const intervals = interval === 15 ? [0, 15, 30, 45, 60] : [0, 30, 60];
const nextMinute = intervals.filter(i => i >= mins)[0];
return hours * 60 + nextMinute;
};
exports.getNextIntervalMinutes = getNextIntervalMinutes;
const makeDates = (startDateStr, days, fmt = exports.HUMAN_DATE) => {
const startDate = (0, exports.dateStrToDate)(startDateStr);
const dateArray = [];
for (let step = 0; step < days + 1; step++) {
const nextDate = (0, date_fns_1.add)(startDate, { days: step });
const value = (0, date_fns_tz_1.format)(nextDate, exports.DATE);
const label = value === (0, exports.todayDate)()
? 'Today'
: value === (0, exports.tomorrowDate)()
? 'Tomorrow'
: (0, date_fns_tz_1.format)(nextDate, fmt);
dateArray.push({ label, value });
}
return dateArray;
};
exports.makeDates = makeDates;
const makeTimes = (date, firstTime, validTimes, holidays, serviceType, leadTime = 0) => {
var _a;
const weekday = (0, exports.dateStrToZonedWeekday)(date);
let times = null;
const holiday = holidays ? holidays[date] : null;
if (holiday) {
times = holiday[serviceType] ? (_a = holiday[serviceType]) === null || _a === void 0 ? void 0 : _a.valid_times : null;
}
else {
const validTime = validTimes[serviceType];
times = validTime ? validTime[weekday] : null;
}
if (!times)
return null;
// if first available date, remove times before first available time
if (date === firstTime.date) {
times = times.filter(t => t.minutes >= firstTime.minutes + leadTime);
}
return times.map(t => ({
name: t.time,
value: t.minutes,
disabled: !t.is_orderable
}));
};
exports.makeTimes = makeTimes;
const makeOrderTimes = (orderTimes, tz) => {
var _a;
const currentDate = new Date();
const withDates = orderTimes === null || orderTimes === void 0 ? void 0 : orderTimes.map(i => {
const { weekday, time } = i.order_by;
let orderByDate = (0, exports.weekdayAndTimeToDate)(weekday, time);
let startDate = (0, exports.weekdayAndTimeToDate)(i.weekday, i.start_time);
// if (orderByDate < currentDate || startDate < currentDate) {
// startDate = add(startDate, { days: 7 })
// }
if (orderByDate < currentDate) {
orderByDate = (0, date_fns_1.add)(orderByDate, { days: 7 });
}
if (startDate < orderByDate) {
startDate = (0, date_fns_1.add)(startDate, { days: 7 });
}
const orderBy = Object.assign(Object.assign({}, i.order_by), { date: orderByDate });
return Object.assign(Object.assign({}, i), { date: startDate, iso: (0, exports.dateToIso)(startDate, tz), order_by: orderBy });
});
return (_a = withDates === null || withDates === void 0 ? void 0 : withDates.sort((a, b) => a.date.getTime() - b.date.getTime())) !== null && _a !== void 0 ? _a : [];
};
exports.makeOrderTimes = makeOrderTimes;
const findOrderTime = (orderTimes, tz, requestedAt) => {
const sortedTimes = (0, exports.makeOrderTimes)(orderTimes, tz);
const selected = requestedAt
? sortedTimes.find(i => i.iso === requestedAt)
: null;
return selected || sortedTimes[0];
};
exports.findOrderTime = findOrderTime;
const makeFirstTime = (revenueCenter, tz, serviceType, requestedAt) => {
var _a;
const { first_times, order_times } = revenueCenter;
const st = serviceType === 'WALKIN' ? 'PICKUP' : serviceType;
if (!first_times || !first_times[st]) {
if (!order_times || !order_times[st] || !((_a = order_times[st]) === null || _a === void 0 ? void 0 : _a.length))
return null;
const selected = (0, exports.findOrderTime)(order_times[st], tz, requestedAt);
return selected.iso;
}
const firstTime = first_times[st];
const firstDate = firstTime ? (0, exports.isoToDate)(firstTime === null || firstTime === void 0 ? void 0 : firstTime.utc, tz) : new Date();
const hasAsap = firstTime === null || firstTime === void 0 ? void 0 : firstTime.has_asap;
if (requestedAt === 'asap' && hasAsap) {
return 'asap';
}
const requestedDate = requestedAt && requestedAt !== 'asap'
? (0, exports.isoToDate)(requestedAt, tz)
: null;
if (requestedDate && requestedDate > firstDate) {
return requestedAt;
}
if (hasAsap && firstTime.minutes % 15 !== 0) {
return 'asap';
}
return firstTime.utc;
};
exports.makeFirstTime = makeFirstTime;
const makeFirstRequestedAt = (revenueCenter, serviceType, requestedAt) => {
const { timezone, revenue_center_type } = revenueCenter;
const tz = exports.timezoneMap[timezone];
const newRequestedAt = requestedAt || (revenue_center_type === 'OLO' ? 'asap' : null);
return (0, exports.makeFirstTime)(revenueCenter, tz, serviceType, newRequestedAt);
};
exports.makeFirstRequestedAt = makeFirstRequestedAt;
const makeFirstTimes = (revenueCenter, serviceType, requestedAt) => {
const { timezone } = revenueCenter;
const settings = revenueCenter;
const tz = exports.timezoneMap[timezone];
const otherServiceType = serviceType === 'DELIVERY' ? 'PICKUP' : 'DELIVERY';
const current = (0, exports.makeFirstTime)(settings, tz, serviceType, requestedAt);
const other = (0, exports.makeFirstTime)(settings, tz, otherServiceType, requestedAt);
if (!current && !other)
return null;
return [
current ? { serviceType: serviceType, requestedAt: current } : null,
other ? { serviceType: otherServiceType, requestedAt: other } : null
];
// return { [serviceType]: current, [otherServiceType]: other }
};
exports.makeFirstTimes = makeFirstTimes;
const getNextInterval = (requestedIso, tz, interval) => {
const date = (0, exports.isoToDate)(requestedIso, tz);
const intervals = interval === 15 ? [0, 15, 30, 45, 60] : [0, 30, 60];
const nextInterval = intervals.filter(i => i >= date.getMinutes())[0];
const hours = nextInterval === 60 ? date.getHours() + 1 : date.getHours();
const minutes = nextInterval === 60 ? 0 : nextInterval;
date.setHours(hours);
date.setMinutes(minutes);
date.setSeconds(0);
date.setMilliseconds(0);
return date;
};
exports.getNextInterval = getNextInterval;
const adjustRequestedAt = (requestedIso, tz, interval, leadTime) => {
const nextDate = (0, exports.getNextInterval)(requestedIso, tz, interval);
const adjusted = (0, date_fns_1.add)(nextDate, { minutes: leadTime });
return (0, exports.dateToIso)(adjusted, tz);
};
exports.adjustRequestedAt = adjustRequestedAt;
const getFirstTime = (revenueCenter, serviceType, tz) => {
var _a;
const { first_times, order_times } = revenueCenter;
const st = serviceType === 'WALKIN' ? 'PICKUP' : serviceType;
if (!first_times || !first_times[st]) {
if (!order_times || !order_times[st])
return null;
const orderTimes = (0, exports.makeOrderTimes)((_a = order_times[st]) !== null && _a !== void 0 ? _a : [], tz);
return orderTimes[0];
}
return first_times[st];
};
exports.getFirstTime = getFirstTime;
const makeGroupOrderTime = (revenueCenter, serviceType, requestedAt) => {
const { timezone } = revenueCenter || {};
const settings = revenueCenter;
const tz = exports.timezoneMap[timezone !== null && timezone !== void 0 ? timezone : 'US/Eastern'];
const { first_times, order_times, wait_times, group_ordering } = settings;
const { prep_time, lead_time } = group_ordering || {};
const st = serviceType === 'WALKIN' ? 'PICKUP' : serviceType;
const waitTime = wait_times && wait_times[st] ? wait_times[st] : 0;
const prepTime = `${(waitTime !== null && waitTime !== void 0 ? waitTime : 0) + (prep_time !== null && prep_time !== void 0 ? prep_time : 0)}`;
if (requestedAt === 'asap')
return { prepTime };
const firstTime = first_times && first_times[st] ? first_times[st] : null;
const orderTimes = order_times && order_times[st] ? order_times[st] : null;
if (!firstTime && !orderTimes)
return null;
let adjustedIso, adjustedDate, cutoffDate, firstIso;
if (orderTimes) {
const orderTime = (0, exports.findOrderTime)(orderTimes, tz, requestedAt);
adjustedIso = orderTime.iso;
adjustedDate = (0, exports.isoToDate)(adjustedIso, tz);
cutoffDate = orderTime.order_by.date;
const allOrderTimes = (0, exports.makeOrderTimes)(orderTimes, tz);
firstIso = allOrderTimes[0].iso;
}
else {
// first available time depends on both suggested lead time and extra prep time
// lead_time = how much time cart guests have to place their orders
// prep_time = how much extra prep time is required for group orders
// over and above the pickup or delivery wait time
if (!firstTime)
return null;
const leadTime = (prep_time !== null && prep_time !== void 0 ? prep_time : 0) + (lead_time !== null && lead_time !== void 0 ? lead_time : 0);
const interval = 15;
firstIso = (0, exports.adjustRequestedAt)(firstTime.utc, tz, interval, leadTime);
const firstDate = (0, exports.isoToDate)(firstIso, tz);
const requestedDate = (0, exports.isoToDate)(requestedAt, tz);
adjustedIso =
requestedDate && requestedDate > firstDate ? requestedAt : firstIso;
adjustedDate = (0, exports.isoToDate)(adjustedIso, tz);
cutoffDate = (0, date_fns_1.sub)(adjustedDate, { minutes: parseFloat(prepTime) });
}
const cutoffIso = (0, exports.dateToIso)(cutoffDate, tz);
return {
isAdjusted: requestedAt !== adjustedIso,
firstIso,
iso: adjustedIso,
date: adjustedDate,
dateStr: (0, exports.makeReadableDateStrFromIso)(adjustedIso, tz, true),
cutoffIso,
cutoffDate,
cutoffDateStr: (0, exports.makeReadableDateStrFromIso)(cutoffIso, tz, true)
};
};
exports.makeGroupOrderTime = makeGroupOrderTime;
const formatTime = (time) => {
return time
? time.replace('Today', 'today').replace('Tomorrow', 'tomorrow')
: '';
};
exports.formatTime = formatTime;
const makeGroupOrderTimeStr = (requestedAt, tz) => {
if (!requestedAt || requestedAt.toLowerCase() === 'asap')
return 'ASAP';
const orderTime = (0, exports.makeReadableDateStrFromIso)(requestedAt, tz, true);
return orderTime ? (0, exports.formatTime)(orderTime) : null;
};
exports.makeGroupOrderTimeStr = makeGroupOrderTimeStr;
const getLastInterval = (tz) => {
const date = (0, exports.isoToDate)(new Date().toISOString(), tz);
date.setHours(23);
date.setMinutes(45);
date.setSeconds(0);
date.setMilliseconds(0);
return date;
};
exports.getLastInterval = getLastInterval;
const makeIntervals = (tz) => {
const nextInterval = (0, exports.getNextInterval)(new Date().toISOString(), tz, 15);
const lastInterval = (0, exports.getLastInterval)(tz);
const diff = Math.max((0, date_fns_1.differenceInMinutes)(lastInterval, nextInterval), 0);
const steps = 24 * 4 + (diff ? Math.ceil(diff / 15) : 0);
let start = (0, date_fns_1.sub)(nextInterval, { minutes: 24 * 60 });
const intervals = [];
for (let step = 0; step < steps; step++) {
const end = (0, date_fns_1.add)(start, { minutes: 15 });
intervals.push({ start, end, orders: [] });
start = end;
}
return intervals;
};
exports.makeIntervals = makeIntervals;
const formatTimeList = (dateStr, tz, includeDate) => {
const date = (0, exports.isoToDate)(dateStr, tz);
const fmt = includeDate ? 'MMM d, h:mma' : 'h:mma';
return (0, date_fns_tz_1.format)(date, fmt).replace('AM', 'am').replace('PM', 'pm');
};
exports.formatTimeList = formatTimeList;
const makeCartDateStr = (requestedAt, tz, waitTime) => {
if (requestedAt === 'asap')
return `Ready in about ${waitTime} minutes`;
const requestedDateStr = (0, exports.isoToDateStr)(requestedAt, tz, 'yyyy-MM-dd');
const now = new Date();
const today = (0, exports.dateToZonedDateStr)(now, tz, 'yyyy-MM-dd');
const tomorrow = (0, exports.dateToZonedDateStr)(now, tz, 'yyyy-MM-dd', 1);
const isToday = requestedDateStr === today;
const isTomorrow = requestedDateStr === tomorrow;
const timeStr = (0, exports.isoToDateStr)(requestedAt, tz, 'h:mma').toLowerCase();
const dateStr = (0, exports.isoToDateStr)(requestedAt, tz, 'EEE, MMM dd');
if (isToday)
return `Ready by ${timeStr}`;
if (isTomorrow)
return `Ready by ${timeStr} tomorrow`;
return `Ready by ${timeStr} on ${dateStr}`;
};
exports.makeCartDateStr = makeCartDateStr;
const makeOrderWindow = (orderTime) => {
if (orderTime.start_time === orderTime.end_time) {
return `@ ${(0, exports.time24ToDateStr)(orderTime.start_time)}`;
}
else {
return `from ${(0, exports.time24ToDateStr)(orderTime.start_time)} to ${(0, exports.time24ToDateStr)(orderTime.end_time)}`;
}
};
exports.makeOrderWindow = makeOrderWindow;