UNPKG

@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
"use strict"; 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;