• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

inclusion-numerique / coop-mediation-numerique / d042ddf5-824b-4a46-8c8f-8237a8853f64

25 Mar 2026 10:41AM UTC coverage: 10.692% (+3.8%) from 6.896%
d042ddf5-824b-4a46-8c8f-8237a8853f64

push

circleci

web-flow
Merge pull request #465 from inclusion-numerique/fix/brevo-shared-contacts

fix(brevo): handle shared Brevo account with Les Bases

699 of 10508 branches covered (6.65%)

Branch coverage included in aggregate %.

18 of 122 new or added lines in 13 files covered. (14.75%)

814 existing lines in 86 files now uncovered.

2168 of 16307 relevant lines covered (13.29%)

2.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/apps/web/src/opening-hours/stringToOpeningHours.ts
1
import {
2
  type Closed,
3
  closed,
4
  type DayOpeningHours,
5
  days,
6
  type OpeningHours,
7
  type Timeslot,
8
  type WeekOpeningHours,
9
} from '@app/web/opening-hours/openingHours'
10
import Oh from 'opening_hours'
11

UNCOV
12
const toOpeningHoursObject = (input: string | null) => {
×
13
  if (!input) return null
×
14

15
  // The lib will throw if no valid osm input is given
16
  try {
×
17
    return new Oh(input)
×
18
  } catch {
19
    return null
×
20
  }
21
}
22

UNCOV
23
const convertIntervalsToDayOpeningHours = (
×
24
  intervals: [Date, Date, boolean, string | undefined][],
25
): DayOpeningHours | Closed => {
26
  // Check for 'off' or empty intervals
27
  if (intervals.length === 0) return null
×
28

29
  const result: DayOpeningHours = { morning: null, afternoon: null }
×
30

31
  for (const [start, end, , state] of intervals) {
×
32
    // Check for explicit 'off'
33
    if (state === 'off') {
×
34
      if (start.getHours() < 12) {
×
35
        result.morning = closed
×
36
      } else {
37
        result.afternoon = closed
×
38
      }
39
      continue
×
40
    }
41

42
    const timeslot: Timeslot = {
×
43
      start: start.toTimeString().slice(0, 5), // Extracts 'HH:MM'
44
      end: end.toTimeString().slice(0, 5),
45
    }
46

47
    if (start.getHours() < 12) {
×
48
      result.morning = timeslot
×
49
    } else {
50
      result.afternoon = timeslot
×
51
    }
52
  }
53

54
  // Consider a day closed if both morning and afternoon are explicitly 'closed'
55
  if (result.morning === closed && result.afternoon === closed) {
×
56
    return closed
×
57
  }
58

59
  return result
×
60
}
61

UNCOV
62
const osmToWeekOpeningHours = (input: Oh): WeekOpeningHours => {
×
63
  const thisMonday = new Date()
×
64
  thisMonday.setDate(
×
65
    thisMonday.getDate() -
66
      thisMonday.getDay() +
67
      (thisMonday.getDay() === 0 ? -6 : 1),
×
68
  )
69
  thisMonday.setHours(0, 0, 0, 0)
×
70

71
  const week: WeekOpeningHours = {
×
72
    monday: null,
73
    tuesday: null,
74
    wednesday: null,
75
    thursday: null,
76
    friday: null,
77
    saturday: null,
78
    sunday: null,
79
  }
80

81
  for (const [dayIndex, day] of days.entries()) {
×
82
    const startDate = new Date(thisMonday)
×
83
    startDate.setDate(thisMonday.getDate() + dayIndex)
×
84
    const endDate = new Date(startDate)
×
85
    endDate.setDate(endDate.getDate() + 1)
×
86

87
    const intervals = input.getOpenIntervals(startDate, endDate)
×
88

89
    week[day as keyof WeekOpeningHours] =
×
90
      convertIntervalsToDayOpeningHours(intervals) ?? null
×
91
  }
92

93
  return week
×
94
}
95

UNCOV
96
export const stringToOpeningHours = (
×
97
  input: string | null,
98
): OpeningHours & { parser: string } => {
99
  if (!input || input.trim().length === 0) {
×
100
    return {
×
101
      comment: null,
102
      week: null,
103
      parser: 'na',
104
    }
105
  }
106

107
  const oh = toOpeningHoursObject(input)
×
108

109
  if (!oh) {
×
110
    // TODO we will use carto's algo to best guess OH format
111
    // From https://github.com/anct-cartographie-nationale/mednum-cli/blob/main/src/transformer/fields/horaires/opening-hours-from-week.ts
112
    // use openingHoursFromWeek()
113

114
    return {
×
115
      comment: input,
116
      week: null,
117
      parser: 'na',
118
    }
119
  }
120

121
  return {
×
122
    comment: oh.getComment() ?? null,
×
123
    week: osmToWeekOpeningHours(oh),
124
    parser: 'oh',
125
  }
126
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc