forked from MapComplete/MapComplete
Fix: opening hours now correctly shows "closes at <point far in the future>"
This commit is contained in:
parent
8584a4ba68
commit
d5b0976fb0
3 changed files with 53 additions and 46 deletions
|
@ -326,6 +326,7 @@
|
||||||
"openTill": "till",
|
"openTill": "till",
|
||||||
"open_24_7": "Open around the clock",
|
"open_24_7": "Open around the clock",
|
||||||
"open_during_ph": "During a public holiday, it is",
|
"open_during_ph": "During a public holiday, it is",
|
||||||
|
"open_until": "Closes at {date}",
|
||||||
"opensAt": "from",
|
"opensAt": "from",
|
||||||
"ph_closed": "closed",
|
"ph_closed": "closed",
|
||||||
"ph_not_known": " ",
|
"ph_not_known": " ",
|
||||||
|
|
|
@ -160,7 +160,7 @@ export class OH {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = newList.length - 1; i >= 0 && doAddEntry; i--) {
|
for (let i = newList.length - 1; i >= 0 && doAddEntry; i--) {
|
||||||
let guard = newList[i]
|
const guard = newList[i]
|
||||||
if (maybeAdd.weekday != guard.weekday) {
|
if (maybeAdd.weekday != guard.weekday) {
|
||||||
// Not the same day
|
// Not the same day
|
||||||
continue
|
continue
|
||||||
|
@ -236,9 +236,8 @@ export class OH {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gives the number of hours since the start of day.
|
* Gives the number of hours since the start of day.
|
||||||
* E.g.
|
*
|
||||||
* startTime({startHour: 9, startMinuts: 15}) == 9.25
|
* // OH.startTime({startHour: 9, startMinutes: 15}) // => 9.25
|
||||||
* @param oh
|
|
||||||
*/
|
*/
|
||||||
public static startTime(oh: OpeningHour): number {
|
public static startTime(oh: OpeningHour): number {
|
||||||
return oh.startHour + oh.startMinutes / 60
|
return oh.startHour + oh.startMinutes / 60
|
||||||
|
@ -346,8 +345,8 @@ export class OH {
|
||||||
const split = rule.trim().replace(/, */g, ",").split(" ")
|
const split = rule.trim().replace(/, */g, ",").split(" ")
|
||||||
if (split.length == 1) {
|
if (split.length == 1) {
|
||||||
// First, try to parse this rule as a rule without weekdays
|
// First, try to parse this rule as a rule without weekdays
|
||||||
let timeranges = OH.ParseHhmmRanges(rule)
|
const timeranges = OH.ParseHhmmRanges(rule)
|
||||||
let weekdays = [0, 1, 2, 3, 4, 5, 6]
|
const weekdays = [0, 1, 2, 3, 4, 5, 6]
|
||||||
return OH.multiply(weekdays, timeranges)
|
return OH.multiply(weekdays, timeranges)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,7 +449,7 @@ export class OH {
|
||||||
return ohs
|
return ohs
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
This function converts a number of ranges (generated by OpeningHours.js) into all the hours of day that a change occurs.
|
This function converts a number of ranges (generated by OpeningHours.js) into all the hours of day that a change occurs.
|
||||||
E.g.
|
E.g.
|
||||||
Monday, some business is opened from 9:00 till 17:00
|
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
|
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 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
|
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(
|
public static allChangeMoments(
|
||||||
ranges: {
|
ranges: {
|
||||||
|
@ -483,8 +487,7 @@ This list will be sorted
|
||||||
startOfDay.setHours(0, 0, 0, 0)
|
startOfDay.setHours(0, 0, 0, 0)
|
||||||
|
|
||||||
// The number of seconds since the start of the day
|
// The number of seconds since the start of the day
|
||||||
// @ts-ignore
|
const changeMoment: number = (range.startDate.getTime() - startOfDay.getTime()) / 1000
|
||||||
const changeMoment: number = (range.startDate - startOfDay) / 1000
|
|
||||||
if (changeHours.indexOf(changeMoment) < 0) {
|
if (changeHours.indexOf(changeMoment) < 0) {
|
||||||
changeHours.push(changeMoment)
|
changeHours.push(changeMoment)
|
||||||
changeHourText.push(
|
changeHourText.push(
|
||||||
|
@ -493,8 +496,7 @@ This list will be sorted
|
||||||
}
|
}
|
||||||
|
|
||||||
// The number of seconds till between the start of the day and closing
|
// The number of seconds till between the start of the day and closing
|
||||||
// @ts-ignore
|
const changeMomentEnd: number = (range.endDate.getTime() - startOfDay.getTime()) / 1000
|
||||||
let changeMomentEnd: number = (range.endDate - startOfDay) / 1000
|
|
||||||
if (changeMomentEnd >= 24 * 60 * 60) {
|
if (changeMomentEnd >= 24 * 60 * 60) {
|
||||||
if (extrachangeHours.indexOf(changeMomentEnd) < 0) {
|
if (extrachangeHours.indexOf(changeMomentEnd) < 0) {
|
||||||
extrachangeHours.push(changeMomentEnd)
|
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[][]
|
ranges: OpeningRange[][]
|
||||||
startingMonday: Date
|
startingMonday: Date
|
||||||
} {
|
} {
|
||||||
const today = new Date()
|
today ??= new Date()
|
||||||
today.setHours(0, 0, 0, 0)
|
today.setHours(0, 0, 0, 0)
|
||||||
const lastMonday = OH.getMondayBefore(today)
|
const lastMonday = OH.getMondayBefore(today)
|
||||||
const nextSunday = new Date(lastMonday)
|
const nextSunday = new Date(lastMonday)
|
||||||
|
@ -699,7 +706,7 @@ This list will be sorted
|
||||||
public static weekdaysIdentical(openingRanges: OpeningRange[][], startday = 0, endday = 4) {
|
public static weekdaysIdentical(openingRanges: OpeningRange[][], startday = 0, endday = 4) {
|
||||||
const monday = openingRanges[startday]
|
const monday = openingRanges[startday]
|
||||||
for (let i = startday + 1; i <= endday; i++) {
|
for (let i = startday + 1; i <= endday; i++) {
|
||||||
let weekday = openingRanges[i]
|
const weekday = openingRanges[i]
|
||||||
if (weekday.length !== monday.length) {
|
if (weekday.length !== monday.length) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -831,12 +838,12 @@ This list will be sorted
|
||||||
}
|
}
|
||||||
return [parsed]
|
return [parsed]
|
||||||
} else if (split.length == 2) {
|
} else if (split.length == 2) {
|
||||||
let start = OH.ParseWeekday(split[0])
|
const start = OH.ParseWeekday(split[0])
|
||||||
let end = OH.ParseWeekday(split[1])
|
const end = OH.ParseWeekday(split[1])
|
||||||
if ((start ?? null) === null || (end ?? null) === null) {
|
if ((start ?? null) === null || (end ?? null) === null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
let range = []
|
const range = []
|
||||||
for (let i = start; i <= end; i++) {
|
for (let i = start; i <= end; i++) {
|
||||||
range.push(i)
|
range.push(i)
|
||||||
}
|
}
|
||||||
|
@ -847,8 +854,8 @@ This list will be sorted
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ParseWeekdayRanges(weekdays: string): number[] {
|
private static ParseWeekdayRanges(weekdays: string): number[] {
|
||||||
let ranges = []
|
const ranges = []
|
||||||
let split = weekdays.split(",")
|
const split = weekdays.split(",")
|
||||||
for (const weekday of split) {
|
for (const weekday of split) {
|
||||||
const parsed = OH.ParseWeekdayRange(weekday)
|
const parsed = OH.ParseWeekdayRange(weekday)
|
||||||
if (parsed === undefined || parsed === null) {
|
if (parsed === undefined || parsed === null) {
|
||||||
|
@ -1054,7 +1061,7 @@ export class ToTextualDescription {
|
||||||
languages[supportedLanguage] = "{a}. {b}"
|
languages[supportedLanguage] = "{a}. {b}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let chainer = new TypedTranslation<{ a; b }>(languages)
|
const chainer = new TypedTranslation<{ a; b }>(languages)
|
||||||
let tr = trs[0]
|
let tr = trs[0]
|
||||||
for (let i = 1; i < trs.length; i++) {
|
for (let i = 1; i < trs.length; i++) {
|
||||||
tr = chainer.PartialSubsTr("a", tr).PartialSubsTr("b", trs[i])
|
tr = chainer.PartialSubsTr("a", tr).PartialSubsTr("b", trs[i])
|
||||||
|
|
|
@ -7,7 +7,7 @@ import BaseUIElement from "../BaseUIElement"
|
||||||
import Toggle from "../Input/Toggle"
|
import Toggle from "../Input/Toggle"
|
||||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||||
import Table from "../Base/Table"
|
import Table from "../Base/Table"
|
||||||
import { Translation } from "../i18n/Translation"
|
import { Translation, TypedTranslation } from "../i18n/Translation"
|
||||||
import Loading from "../Base/Loading"
|
import Loading from "../Base/Loading"
|
||||||
import opening_hours from "opening_hours"
|
import opening_hours from "opening_hours"
|
||||||
import Locale from "../i18n/Locale"
|
import Locale from "../i18n/Locale"
|
||||||
|
@ -73,7 +73,7 @@ export default class OpeningHoursVisualization extends Toggle {
|
||||||
ranges: OpeningRange[][],
|
ranges: OpeningRange[][],
|
||||||
lastMonday: Date
|
lastMonday: Date
|
||||||
): BaseUIElement {
|
): 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)) {
|
if (ranges.some((range) => range.length > 0)) {
|
||||||
// The normal case: we have items for the coming days
|
// The normal case: we have items for the coming days
|
||||||
return OpeningHoursVisualization.ConstructVizTable(oh, ranges, lastMonday)
|
return OpeningHoursVisualization.ConstructVizTable(oh, ranges, lastMonday)
|
||||||
|
@ -98,8 +98,7 @@ export default class OpeningHoursVisualization extends Toggle {
|
||||||
const today = new Date()
|
const today = new Date()
|
||||||
today.setHours(0, 0, 0, 0)
|
today.setHours(0, 0, 0, 0)
|
||||||
|
|
||||||
// @ts-ignore
|
const todayIndex = Math.ceil((today.getTime() - rangeStart.getTime()) / (1000 * 60 * 60 * 24))
|
||||||
const todayIndex = Math.ceil((today - rangeStart) / (1000 * 60 * 60 * 24))
|
|
||||||
// By default, we always show the range between 8 - 19h, in order to give a stable impression
|
// 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
|
// Ofc, a bigger range is used if needed
|
||||||
const earliestOpen = Math.min(8 * 60 * 60, ...changeHours)
|
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)
|
const startOfDay: Date = new Date(range.startDate)
|
||||||
startOfDay.setHours(0, 0, 0, 0)
|
startOfDay.setHours(0, 0, 0, 0)
|
||||||
// @ts-ignore
|
const startpoint = (range.startDate.getTime() - startOfDay.getTime()) / 1000 - earliestOpen
|
||||||
const startpoint = (range.startDate - startOfDay) / 1000 - earliestOpen
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
// @ts-ignore
|
const width = (100 * (range.endDate.getTime() - range.startDate.getTime()) / 1000) / (latestclose - earliestOpen)
|
||||||
const width = (100 * (range.endDate - range.startDate) / 1000) / (latestclose - earliestOpen);
|
|
||||||
const startPercentage = (100 * startpoint) / availableArea
|
const startPercentage = (100 * startpoint) / availableArea
|
||||||
return new FixedUiElement(textToShow)
|
return new FixedUiElement(textToShow)
|
||||||
.SetStyle(`left:${startPercentage}%; width:${width}%`)
|
.SetStyle(`left:${startPercentage}%; width:${width}%`)
|
||||||
|
@ -236,7 +233,7 @@ export default class OpeningHoursVisualization extends Toggle {
|
||||||
changeHourText: string[],
|
changeHourText: string[],
|
||||||
earliestOpen: number
|
earliestOpen: number
|
||||||
): [BaseUIElement, string] {
|
): [BaseUIElement, string] {
|
||||||
let header: BaseUIElement[] = []
|
const header: BaseUIElement[] = []
|
||||||
|
|
||||||
header.push(
|
header.push(
|
||||||
...OpeningHoursVisualization.CreateLinesAtChangeHours(
|
...OpeningHoursVisualization.CreateLinesAtChangeHours(
|
||||||
|
@ -249,7 +246,7 @@ export default class OpeningHoursVisualization extends Toggle {
|
||||||
let showHigher = false
|
let showHigher = false
|
||||||
let showHigherUsed = false
|
let showHigherUsed = false
|
||||||
for (let i = 0; i < changeHours.length; i++) {
|
for (let i = 0; i < changeHours.length; i++) {
|
||||||
let changeMoment = changeHours[i]
|
const changeMoment = changeHours[i]
|
||||||
const offset = (100 * (changeMoment - earliestOpen)) / availableArea
|
const offset = (100 * (changeMoment - earliestOpen)) / availableArea
|
||||||
if (offset < 0 || offset > 100) {
|
if (offset < 0 || offset > 100) {
|
||||||
continue
|
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, ...
|
* Visualizes any special case: e.g. not open for a long time, 24/7 open, ...
|
||||||
* */
|
* */
|
||||||
private static ShowSpecialCase(oh: any) {
|
private static ShowSpecialCase(oh: opening_hours) {
|
||||||
const opensAtDate = oh.getNextChange()
|
const nextChange = oh.getNextChange()
|
||||||
if (opensAtDate === undefined) {
|
if (nextChange !== undefined) {
|
||||||
const comm = oh.getComment() ?? oh.getUnknown()
|
const nowOpen = oh.getState(new Date())
|
||||||
if (!!comm) {
|
const t = Translations.t.general.opening_hours
|
||||||
return new FixedUiElement(comm)
|
const tr: TypedTranslation<{ date }> = nowOpen ? t.open_until : t.closed_until
|
||||||
}
|
const date = nextChange.toLocaleString()
|
||||||
|
return tr.Subs({ date })
|
||||||
if (oh.getState()) {
|
|
||||||
return Translations.t.general.opening_hours.open_24_7.Clone()
|
|
||||||
}
|
|
||||||
return Translations.t.general.opening_hours.closed_permanently.Clone()
|
|
||||||
}
|
}
|
||||||
return Translations.t.general.opening_hours.closed_until.Subs({
|
const comment = oh.getComment() ?? oh.getUnknown()
|
||||||
date: opensAtDate.toLocaleString(),
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue