{"version":3,"file":"nonApiBookableTimes-060c87cc.js","sources":["../../../../app/frontend/components/b2c/directory/nonApiBookableTimes.js"],"sourcesContent":["import { trackDOMEvent } from '~/components/shared/tracking/segmentAnalytics';\nimport {\n ONE_MINUTE,\n ONE_HOUR,\n ONE_DAY,\n combineDateTime,\n addTime,\n getDatestring,\n formatTime,\n} from '../../shared/dateUtilities';\n\n\n// Get a time 15 minutes in the future\nconst getNextTime = (date) => new Date(date.getTime() + 15 * ONE_MINUTE);\n\nconst getFirstPossibleTime = (startTime = new Date()) => {\n // round to the nearest 15 minute interval\n let firstPossibleTime =\n Math.round(startTime.getTime() / (15 * ONE_MINUTE)) * 15 * ONE_MINUTE;\n if (firstPossibleTime - startTime.getTime() < 30 * ONE_MINUTE) {\n firstPossibleTime = new Date(firstPossibleTime + 15 * ONE_MINUTE);\n }\n return firstPossibleTime;\n};\n\n\ndocument.querySelectorAll('[data-booking-times-controller]').forEach(controllerEl => {\n // Find cards that need fake times and do those\n controllerEl.querySelectorAll('[data-booking-times-fake-card]').forEach(card => {\n const dataset = card.dataset;\n const max_times = parseInt(dataset.numberOfBookingTimes) || 4;\n if (typeof dataset.alwaysOpen !== \"undefined\") {\n const href = dataset.bookableTimesHref;\n const buttonsWrapperEl = card.querySelector(\n \"[data-bookable-buttons-wrapper]\"\n );\n const firstPossibleTime = getFirstPossibleTime();\n const seeMoreText = dataset.seeMoreText || \"See more\";\n const times = [];\n\n times.push(firstPossibleTime);\n\n let nextTime = getNextTime(firstPossibleTime);\n while (times.length < max_times) {\n times.push(nextTime);\n nextTime = getNextTime(nextTime);\n }\n\n const segmentEvent = dataset.bookableEvent;\n const segmentAction = \"click bookable time\";\n\n const createButtonLink = (\n time,\n href\n ) => `${formatTime(\n time\n )}`;\n\n const createSeeMoreLink = (href) =>\n `${seeMoreText}`;\n\n const buttons = [\n ...times.map((time) => createButtonLink(time, href)),\n createSeeMoreLink(href),\n ];\n\n buttonsWrapperEl.innerHTML = buttons.join(\"\");\n const listingProperties = getElementProperties(card);\n buttonsWrapperEl.querySelectorAll(\"a\").forEach((el) => {\n el.addEventListener(\"click\", (event) =>\n trackDOMEvent(event, listingProperties)\n );\n });\n } else {\n const hasHours = (hoursString) => {\n const noHoursStrings = [\"Unknown\", \"Closed\"];\n for (const noString of noHoursStrings) {\n if (hoursString.includes(noString)) {\n return false;\n }\n }\n return true;\n };\n\n const parseHoursString = (hoursString) => {\n const dayName = hoursString.substr(0, 3);\n\n const [startTime, endTime] = hoursString\n .substr(3)\n .split(\"-\")\n .map((s) => s.trim());\n return [dayName, startTime, endTime];\n };\n\n // check the time isn't too close to closing\n const isTimeValid = (time, closeTime) => closeTime - time >= 15 * ONE_MINUTE;\n\n let hoursList;\n let todaysHours;\n\n if (dataset.fakeHours === 'true') {\n hoursList = [\n \"Mon 9:00 am - 5:00 pm\",\n \"Tue 9:00 am - 5:00 pm\",\n \"Wed 9:00 am - 5:00 pm\",\n \"Thu 9:00 am - 5:00 pm\",\n \"Fri 9:00 am - 5:00 pm\",\n \"Sat 9:00 am - 5:00 pm\",\n \"Sun 9:00 am - 5:00 pm\",\n ];\n const todayDayName = new Date().toLocaleDateString(\"en-US\", {\n weekday: \"short\",\n });\n todaysHours = hoursList.find((hoursString) =>\n hoursString.includes(todayDayName)\n );\n } else {\n hoursList = Array.from(\n card.querySelector(\"[data-hours-list]\").children\n ).map((el) => el.innerText);\n\n todaysHours = card.querySelector(\n \".unified_listing-card__current-hours\"\n )?.dataset.todaysHours;\n\n }\n\n const getNextOpenHours = () => {\n const todayDayName = new Date().toLocaleDateString(\"en-US\", {\n weekday: \"short\",\n });\n const todayIndex = hoursList.findIndex((hoursString) =>\n hoursString.includes(todayDayName)\n );\n\n let nextDayIndex = todayIndex + 1;\n let nextDayHours = hoursList[nextDayIndex % hoursList.length];\n\n while (!hasHours(nextDayHours)) {\n nextDayIndex += 1;\n nextDayHours = hoursList[nextDayIndex % hoursList.length];\n }\n\n const [_day, startTime, endTime] = parseHoursString(nextDayHours);\n const nextDayDate = addTime((nextDayIndex - todayIndex) * ONE_DAY);\n const openingTime = combineDateTime(nextDayDate, startTime);\n const closingTime = combineDateTime(nextDayDate, endTime);\n return [openingTime, closingTime];\n };\n\n // Get the first valid opening/closing times\n const getOpeningAndClosing = (currentTime) => {\n if (todaysHours && hasHours(todaysHours)) {\n const [_day, startTime, endTime] = parseHoursString(todaysHours);\n const openingTime = combineDateTime(new Date(), startTime);\n const closingTime = combineDateTime(new Date(), endTime);\n // need to check if we're too close to closing time, if so we need to just move on and get the next days opening time\n if (isTimeValid(getFirstPossibleTime(currentTime), closingTime)) {\n return [openingTime, closingTime];\n }\n }\n return getNextOpenHours();\n };\n\n // Get title text for availability\n const getTitle = (time, times_name = \"times\") => {\n const currentDatestring = getDatestring();\n const firstTimeDatestring = getDatestring(time);\n const tomorrowDatestring = getDatestring(addTime(ONE_DAY));\n\n if (currentDatestring === firstTimeDatestring) {\n return `Available ${times_name} today`;\n }\n if (currentDatestring === tomorrowDatestring) {\n return `Available ${times_name} tomorrow`;\n }\n\n const dayName = time.toLocaleDateString(\"en-US\", { weekday: \"long\" });\n return `Available ${times_name} on ${dayName}`;\n };\n\n const getSegmentActionDay = (time) =>\n getTitle(time).includes(\"today\") ? \"today\" : \"tomorrow\";\n\n const getSegmentAction = (time) => {\n return `click bookable time - ${getSegmentActionDay(time)}`;\n };\n\n const getSegmentProperties = () => {\n let props = \"\";\n if (card.dataset.segmentCardRank) {\n props += `data-segment-card-rank=\"${card.dataset.segmentCardRank}\" `;\n }\n if (card.dataset.segmentLocationId) {\n props += `data-segment-location-id=\"${card.dataset.segmentLocationId}\"`;\n }\n return props;\n };\n\n const setTarget = (href) => {\n if (href === 'javascript:void(0);') {\n return '';\n }\n return '_blank';\n }\n\n const createButtonLink = (time, href, event = \"Directory - CDP Card\") => {\n\n return `${formatTime(time)}`;\n\n }\n const renderNoTimes = () => {\n const timesContainer = card.querySelector(\n \".unified-listing-card__bookable-times\"\n );\n\n const title = \"No available times today or tomorrow\";\n\n const titleEl = `

${title}

`;\n const buttonsWrapper = `
`;\n timesContainer.innerHTML = titleEl + buttonsWrapper;\n };\n\n // first check if the location has no hours\n if (typeof card.dataset.hasNoHours !== \"undefined\") {\n renderNoTimes();\n } else {\n // Handle timezone offsets\n let timezoneOffset = 0;\n if (card.dataset.timezoneOffset) {\n timezoneOffset = parseInt(card.dataset.timezoneOffset);\n }\n\n const localOffset = new Date().getTimezoneOffset() / 60;\n\n // this is the offset we need to add to local time to compare to hours list times in ms\n const timeOffset = (timezoneOffset + localOffset) * ONE_HOUR;\n\n // first we will make an array of times to show\n const times = [];\n const currentTime = new Date(new Date().getTime() + timeOffset);\n const [openTime, closeTime] = getOpeningAndClosing(currentTime);\n let firstPossibleTime;\n // if open time is in the future, use the open time for first possible\n if (currentTime < openTime) {\n firstPossibleTime = getFirstPossibleTime(openTime);\n } else {\n firstPossibleTime = getFirstPossibleTime(currentTime);\n }\n\n // check if firstPossibleTime is more than 2 days away\n const dayAfterTomorrow = getDatestring(addTime(2 * ONE_DAY));\n if (dayAfterTomorrow <= getDatestring(firstPossibleTime) && card.dataset.segmentGroupId !== \"LeOBVQ\") {\n return renderNoTimes();\n }\n\n times.push(firstPossibleTime);\n\n let nextTime = getNextTime(firstPossibleTime);\n\n while (isTimeValid(nextTime, closeTime) && times.length < max_times) {\n times.push(nextTime);\n nextTime = getNextTime(nextTime);\n }\n\n const href = card.dataset.permalink;\n\n let segmentEvent = \"Directory - CDP Card\";\n\n const isInPersonAd = card.classList.contains(\"solv-plus-in-person-listing\");\n\n if (isInPersonAd) {\n segmentEvent = \"Directory - CTA\";\n } else if (card.dataset.segmentEvent) {\n segmentEvent = card.dataset.segmentEvent;\n }\n\n const buttons = [\n ...times\n .map((time) => createButtonLink(time, href, segmentEvent)),\n `See more
times
`,\n ];\n\n const timesContainer = card.querySelector(\n \".unified-listing-card__bookable-times\"\n );\n\n const times_name = isInPersonAd ? \"in-person visit times\" : \"times\";\n const title = getTitle(times[0], times_name);\n\n const titleEl = `

${title}

`;\n const buttonsWrapper = `
${buttons.join(\n \"\"\n )}
`;\n timesContainer.innerHTML = titleEl + buttonsWrapper;\n\n timesContainer.querySelectorAll(\"a\").forEach((el) => {\n el.addEventListener(\"click\", (event) => trackDOMEvent(event));\n });\n }\n }\n });\n});\n\n\n"],"names":["getNextTime","date","ONE_MINUTE","getFirstPossibleTime","startTime","firstPossibleTime","controllerEl","card","dataset","max_times","href","buttonsWrapperEl","seeMoreText","times","nextTime","segmentEvent","segmentAction","createButtonLink","time","formatTime","createSeeMoreLink","buttons","listingProperties","el","event","trackDOMEvent","hasHours","hoursString","noHoursStrings","noString","parseHoursString","dayName","endTime","s","isTimeValid","closeTime","hoursList","todaysHours","todayDayName","_a","getNextOpenHours","todayIndex","nextDayIndex","nextDayHours","_day","nextDayDate","addTime","ONE_DAY","openingTime","combineDateTime","closingTime","getOpeningAndClosing","currentTime","getTitle","times_name","currentDatestring","getDatestring","firstTimeDatestring","tomorrowDatestring","getSegmentActionDay","getSegmentAction","getSegmentProperties","props","setTarget","renderNoTimes","timesContainer","titleEl","buttonsWrapper","timezoneOffset","localOffset","timeOffset","ONE_HOUR","openTime","isInPersonAd"],"mappings":"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"}