From d5b0976fb0b1df68772146d3e972bd245672951a Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Sun, 20 Apr 2025 00:53:33 +0200 Subject: [PATCH] Fix: opening hours now correctly shows "closes at " --- langs/en.json | 1 + src/UI/OpeningHours/OpeningHours.ts | 49 +++++++++++-------- .../OpeningHours/OpeningHoursVisualization.ts | 49 +++++++++---------- 3 files changed, 53 insertions(+), 46 deletions(-) diff --git a/langs/en.json b/langs/en.json index 456326f91..3e55ff894 100644 --- a/langs/en.json +++ b/langs/en.json @@ -326,6 +326,7 @@ "openTill": "till", "open_24_7": "Open around the clock", "open_during_ph": "During a public holiday, it is", + "open_until": "Closes at {date}", "opensAt": "from", "ph_closed": "closed", "ph_not_known": " ", diff --git a/src/UI/OpeningHours/OpeningHours.ts b/src/UI/OpeningHours/OpeningHours.ts index 527c793fd..0c4a32dfb 100644 --- a/src/UI/OpeningHours/OpeningHours.ts +++ b/src/UI/OpeningHours/OpeningHours.ts @@ -160,7 +160,7 @@ export class OH { } for (let i = newList.length - 1; i >= 0 && doAddEntry; i--) { - let guard = newList[i] + const guard = newList[i] if (maybeAdd.weekday != guard.weekday) { // Not the same day continue @@ -236,9 +236,8 @@ export class OH { /** * Gives the number of hours since the start of day. - * E.g. - * startTime({startHour: 9, startMinuts: 15}) == 9.25 - * @param oh + * + * // OH.startTime({startHour: 9, startMinutes: 15}) // => 9.25 */ public static startTime(oh: OpeningHour): number { return oh.startHour + oh.startMinutes / 60 @@ -346,8 +345,8 @@ export class OH { const split = rule.trim().replace(/, */g, ",").split(" ") if (split.length == 1) { // First, try to parse this rule as a rule without weekdays - let timeranges = OH.ParseHhmmRanges(rule) - let weekdays = [0, 1, 2, 3, 4, 5, 6] + const timeranges = OH.ParseHhmmRanges(rule) + const weekdays = [0, 1, 2, 3, 4, 5, 6] return OH.multiply(weekdays, timeranges) } @@ -450,7 +449,7 @@ export class OH { return ohs } - /* + /** This function converts a number of ranges (generated by OpeningHours.js) into all the hours of day that a change occurs. E.g. Monday, some business is opened from 9:00 till 17:00 @@ -458,6 +457,11 @@ Tuesday from 9:30 till 18:00 Wednesday from 9:30 till 12:30 This function will extract all those moments of change and will return 9:00, 9:30, 12:30, 17:00 and 18:00 This list will be sorted + +const startDate = new Date(2025,4,20,10,0,0) +const endDate = new Date(2025,4,20,17,0,0) +const changes = OH.allChangeMoments([[{isOpen: true, isSpecial: false, comment: "", startDate, endDate}]]) +changes // => [[36000,61200], ["10:00", "17:00"]] */ public static allChangeMoments( ranges: { @@ -483,8 +487,7 @@ This list will be sorted startOfDay.setHours(0, 0, 0, 0) // The number of seconds since the start of the day - // @ts-ignore - const changeMoment: number = (range.startDate - startOfDay) / 1000 + const changeMoment: number = (range.startDate.getTime() - startOfDay.getTime()) / 1000 if (changeHours.indexOf(changeMoment) < 0) { changeHours.push(changeMoment) changeHourText.push( @@ -493,8 +496,7 @@ This list will be sorted } // The number of seconds till between the start of the day and closing - // @ts-ignore - let changeMomentEnd: number = (range.endDate - startOfDay) / 1000 + const changeMomentEnd: number = (range.endDate.getTime() - startOfDay.getTime()) / 1000 if (changeMomentEnd >= 24 * 60 * 60) { if (extrachangeHours.indexOf(changeMomentEnd) < 0) { extrachangeHours.push(changeMomentEnd) @@ -665,13 +667,18 @@ This list will be sorted */ /** - * Constructs the opening-ranges for either this week, or for next week if there are no more openings this week + * Constructs the opening-ranges for either this week, or for next week if there are no more openings this week. + * Note: 'today' is mostly used for testing + * + * const oh = new opening_hours("mar 15 - oct 15") + * const ranges = OH.createRangesForApplicableWeek(oh, new Date(2025,4,20,10,0,0)) + * ranges // => {ranges: [[],[],[],[],[],[]], startingMonday: new Date(2025,4,18,10,0,0)} */ - public static createRangesForApplicableWeek(oh: opening_hours): { + public static createRangesForApplicableWeek(oh: opening_hours, today?: Date): { ranges: OpeningRange[][] startingMonday: Date } { - const today = new Date() + today ??= new Date() today.setHours(0, 0, 0, 0) const lastMonday = OH.getMondayBefore(today) const nextSunday = new Date(lastMonday) @@ -699,7 +706,7 @@ This list will be sorted public static weekdaysIdentical(openingRanges: OpeningRange[][], startday = 0, endday = 4) { const monday = openingRanges[startday] for (let i = startday + 1; i <= endday; i++) { - let weekday = openingRanges[i] + const weekday = openingRanges[i] if (weekday.length !== monday.length) { return false } @@ -831,12 +838,12 @@ This list will be sorted } return [parsed] } else if (split.length == 2) { - let start = OH.ParseWeekday(split[0]) - let end = OH.ParseWeekday(split[1]) + const start = OH.ParseWeekday(split[0]) + const end = OH.ParseWeekday(split[1]) if ((start ?? null) === null || (end ?? null) === null) { return null } - let range = [] + const range = [] for (let i = start; i <= end; i++) { range.push(i) } @@ -847,8 +854,8 @@ This list will be sorted } private static ParseWeekdayRanges(weekdays: string): number[] { - let ranges = [] - let split = weekdays.split(",") + const ranges = [] + const split = weekdays.split(",") for (const weekday of split) { const parsed = OH.ParseWeekdayRange(weekday) if (parsed === undefined || parsed === null) { @@ -1054,7 +1061,7 @@ export class ToTextualDescription { languages[supportedLanguage] = "{a}. {b}" } } - let chainer = new TypedTranslation<{ a; b }>(languages) + const chainer = new TypedTranslation<{ a; b }>(languages) let tr = trs[0] for (let i = 1; i < trs.length; i++) { tr = chainer.PartialSubsTr("a", tr).PartialSubsTr("b", trs[i]) diff --git a/src/UI/OpeningHours/OpeningHoursVisualization.ts b/src/UI/OpeningHours/OpeningHoursVisualization.ts index c513a44dd..73f2c6a74 100644 --- a/src/UI/OpeningHours/OpeningHoursVisualization.ts +++ b/src/UI/OpeningHours/OpeningHoursVisualization.ts @@ -7,7 +7,7 @@ import BaseUIElement from "../BaseUIElement" import Toggle from "../Input/Toggle" import { VariableUiElement } from "../Base/VariableUIElement" import Table from "../Base/Table" -import { Translation } from "../i18n/Translation" +import { Translation, TypedTranslation } from "../i18n/Translation" import Loading from "../Base/Loading" import opening_hours from "opening_hours" import Locale from "../i18n/Locale" @@ -73,7 +73,7 @@ export default class OpeningHoursVisualization extends Toggle { ranges: OpeningRange[][], lastMonday: Date ): BaseUIElement { - // First, a small sanity check. The business might be permanently closed, 24/7 opened or something other special + // First, a small sanity check. The business might be permanently closed, 24/7 opened or be another special case if (ranges.some((range) => range.length > 0)) { // The normal case: we have items for the coming days return OpeningHoursVisualization.ConstructVizTable(oh, ranges, lastMonday) @@ -98,8 +98,7 @@ export default class OpeningHoursVisualization extends Toggle { const today = new Date() today.setHours(0, 0, 0, 0) - // @ts-ignore - const todayIndex = Math.ceil((today - rangeStart) / (1000 * 60 * 60 * 24)) + const todayIndex = Math.ceil((today.getTime() - rangeStart.getTime()) / (1000 * 60 * 60 * 24)) // By default, we always show the range between 8 - 19h, in order to give a stable impression // Ofc, a bigger range is used if needed const earliestOpen = Math.min(8 * 60 * 60, ...changeHours) @@ -193,11 +192,9 @@ export default class OpeningHoursVisualization extends Toggle { const startOfDay: Date = new Date(range.startDate) startOfDay.setHours(0, 0, 0, 0) - // @ts-ignore - const startpoint = (range.startDate - startOfDay) / 1000 - earliestOpen + const startpoint = (range.startDate.getTime() - startOfDay.getTime()) / 1000 - earliestOpen // prettier-ignore - // @ts-ignore - const width = (100 * (range.endDate - range.startDate) / 1000) / (latestclose - earliestOpen); + const width = (100 * (range.endDate.getTime() - range.startDate.getTime()) / 1000) / (latestclose - earliestOpen) const startPercentage = (100 * startpoint) / availableArea return new FixedUiElement(textToShow) .SetStyle(`left:${startPercentage}%; width:${width}%`) @@ -236,7 +233,7 @@ export default class OpeningHoursVisualization extends Toggle { changeHourText: string[], earliestOpen: number ): [BaseUIElement, string] { - let header: BaseUIElement[] = [] + const header: BaseUIElement[] = [] header.push( ...OpeningHoursVisualization.CreateLinesAtChangeHours( @@ -249,7 +246,7 @@ export default class OpeningHoursVisualization extends Toggle { let showHigher = false let showHigherUsed = false for (let i = 0; i < changeHours.length; i++) { - let changeMoment = changeHours[i] + const changeMoment = changeHours[i] const offset = (100 * (changeMoment - earliestOpen)) / availableArea if (offset < 0 || offset > 100) { continue @@ -285,21 +282,23 @@ export default class OpeningHoursVisualization extends Toggle { /* * Visualizes any special case: e.g. not open for a long time, 24/7 open, ... * */ - private static ShowSpecialCase(oh: any) { - const opensAtDate = oh.getNextChange() - if (opensAtDate === undefined) { - const comm = oh.getComment() ?? oh.getUnknown() - if (!!comm) { - return new FixedUiElement(comm) - } - - if (oh.getState()) { - return Translations.t.general.opening_hours.open_24_7.Clone() - } - return Translations.t.general.opening_hours.closed_permanently.Clone() + private static ShowSpecialCase(oh: opening_hours) { + const nextChange = oh.getNextChange() + if (nextChange !== undefined) { + const nowOpen = oh.getState(new Date()) + const t = Translations.t.general.opening_hours + const tr: TypedTranslation<{ date }> = nowOpen ? t.open_until : t.closed_until + const date = nextChange.toLocaleString() + return tr.Subs({ date }) } - return Translations.t.general.opening_hours.closed_until.Subs({ - date: opensAtDate.toLocaleString(), - }) + const comment = oh.getComment() ?? oh.getUnknown() + if (typeof comment === "string") { + return new FixedUiElement(comment) + } + + if (oh.getState()) { + return Translations.t.general.opening_hours.open_24_7.Clone() + } + return Translations.t.general.opening_hours.closed_permanently.Clone() } }