@ancon/wildcat-utils 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ export * from './shared';
2
+ export * from './outlet';
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ __exportStar(require("./shared"), exports);
14
+ __exportStar(require("./outlet"), exports);
@@ -0,0 +1,31 @@
1
+ import { ListOutlet } from './types';
2
+ declare type ReadableOrderFormat = {
3
+ id: number;
4
+ name: string;
5
+ };
6
+ declare type ISOString = string;
7
+ export declare type FormattedInterval = {
8
+ id: string;
9
+ start: ISOString;
10
+ end: ISOString;
11
+ reason?: string;
12
+ };
13
+ declare type OpeningHours = {
14
+ isoWeekday: number;
15
+ key: string;
16
+ open: FormattedInterval[];
17
+ adjusted: FormattedInterval[];
18
+ closed: FormattedInterval[];
19
+ };
20
+ export declare type OpeningHoursTable = {
21
+ orderFormats: ReadableOrderFormat[];
22
+ openingHours: OpeningHours[];
23
+ };
24
+ /**
25
+ * Get an array of opening hours divided by order formats
26
+ * @param outlet Outlet from nearby endpoint
27
+ * @param nowISOString Optional ISO date string of current datetime
28
+ * @returns Opening hours table
29
+ */
30
+ export default function getListOutletOpeningHoursTable(outlet: ListOutlet, nowISOString?: string): OpeningHoursTable[];
31
+ export {};
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const moment_1 = __importDefault(require("moment"));
7
+ const __1 = require("..");
8
+ const ORDER_FORMATS = [
9
+ { id: __1.OrderFormat.EatIn, name: 'eatIn' },
10
+ { id: __1.OrderFormat.Takeaway, name: 'takeaway' },
11
+ { id: __1.OrderFormat.TableOrder, name: 'tableOrder' },
12
+ { id: __1.OrderFormat.Delivery, name: 'delivery' },
13
+ ];
14
+ function generateWeekFromToday(nowISOString) {
15
+ const today = moment_1.default.utc(nowISOString).subtract(1, 'day').startOf('day');
16
+ const result = [];
17
+ for (let i = 0, current = today; i < 7; i += 1) {
18
+ current = current.clone().add(1, 'day').startOf('day');
19
+ result.push(current.clone());
20
+ }
21
+ return result;
22
+ }
23
+ function sortByIsoWeekday(moments) {
24
+ return [...moments].sort((a, b) => a.isoWeekday() - b.isoWeekday());
25
+ }
26
+ function getIntervalTimestampAsNumbers(timestamp) {
27
+ return timestamp.split(':').map(Number);
28
+ }
29
+ function formatInterval(interval, weekdayMoment) {
30
+ const [startHour, startMinute] = getIntervalTimestampAsNumbers(interval.start);
31
+ const [durationHour, durationMinute] = getIntervalTimestampAsNumbers(interval.duration);
32
+ if (interval.type === __1.IntervalType.Interval) {
33
+ const startMoment = weekdayMoment
34
+ .clone()
35
+ .add(startHour, 'hour')
36
+ .add(startMinute, 'minute');
37
+ const endMoment = startMoment
38
+ .clone()
39
+ .add(durationHour, 'hour')
40
+ .add(durationMinute, 'minute');
41
+ return {
42
+ id: interval.id,
43
+ start: startMoment.toISOString(),
44
+ end: endMoment.toISOString(),
45
+ };
46
+ }
47
+ if (interval.type === __1.IntervalType.Exception) {
48
+ const fromDateMoment = (0, moment_1.default)(interval.fromDate);
49
+ const toDateMoment = (0, moment_1.default)(interval.toDate);
50
+ if (weekdayMoment.isBetween(fromDateMoment, toDateMoment, undefined, '[]')) {
51
+ const startMoment = weekdayMoment
52
+ .clone()
53
+ .add(startHour, 'hour')
54
+ .add(startMinute, 'minute');
55
+ const endMoment = startMoment
56
+ .clone()
57
+ .add(durationHour, 'hour')
58
+ .add(durationMinute, 'minute');
59
+ return {
60
+ id: interval.id,
61
+ start: startMoment.toISOString(),
62
+ end: endMoment.toISOString(),
63
+ reason: interval.reason,
64
+ };
65
+ }
66
+ return null;
67
+ }
68
+ throw new Error('Invalid interval type');
69
+ }
70
+ function collectReadableInterval(interval, week, collector) {
71
+ var _a;
72
+ const weekdayIsoMap = {
73
+ [__1.DayOfWeek.Monday]: 1,
74
+ [__1.DayOfWeek.Tuesday]: 2,
75
+ [__1.DayOfWeek.Wednesday]: 3,
76
+ [__1.DayOfWeek.Thursday]: 4,
77
+ [__1.DayOfWeek.Friday]: 5,
78
+ [__1.DayOfWeek.Saturday]: 6,
79
+ [__1.DayOfWeek.Sunday]: 7,
80
+ };
81
+ for (let i = 0; i < week.length; i += 1) {
82
+ const weekdayMoment = week[i];
83
+ const momentIsoWeekday = weekdayMoment.isoWeekday();
84
+ const intervalWeekdayEnum = interval.dayOfWeek;
85
+ const intervalIsoWeekday = (_a = weekdayIsoMap[intervalWeekdayEnum]) !== null && _a !== void 0 ? _a : null;
86
+ const intervalIsApplicableToday = intervalIsoWeekday === momentIsoWeekday ||
87
+ intervalWeekdayEnum === __1.DayOfWeek.Everyday;
88
+ if (!collector[momentIsoWeekday]) {
89
+ // eslint-disable-next-line no-param-reassign
90
+ collector[momentIsoWeekday] = {
91
+ isoWeekday: momentIsoWeekday,
92
+ key: '',
93
+ open: [],
94
+ adjusted: [],
95
+ closed: [],
96
+ };
97
+ }
98
+ if (intervalIsApplicableToday) {
99
+ const formattedInterval = formatInterval(interval, weekdayMoment);
100
+ if (formattedInterval) {
101
+ // eslint-disable-next-line no-param-reassign
102
+ collector[momentIsoWeekday].key += formattedInterval.id;
103
+ if (interval.type === __1.IntervalType.Interval &&
104
+ interval.state === __1.IntervalState.Open) {
105
+ collector[momentIsoWeekday].open.push(formattedInterval);
106
+ }
107
+ else if (interval.type === __1.IntervalType.Interval &&
108
+ interval.state === __1.IntervalState.Closed) {
109
+ collector[momentIsoWeekday].closed.push(formattedInterval);
110
+ }
111
+ else if (interval.type === __1.IntervalType.Exception &&
112
+ interval.state === __1.IntervalState.Open) {
113
+ collector[momentIsoWeekday].adjusted.push(formattedInterval);
114
+ }
115
+ else if (interval.type === __1.IntervalType.Exception &&
116
+ interval.state === __1.IntervalState.Closed) {
117
+ collector[momentIsoWeekday].closed.push(formattedInterval);
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+ function generateIntervalId(interval) {
124
+ switch (interval.type) {
125
+ case __1.IntervalType.Exception:
126
+ return (0, __1.generateId)('interval-exception');
127
+ case __1.IntervalType.Interval:
128
+ return (0, __1.generateId)('interval-normal');
129
+ default:
130
+ return (0, __1.generateId)('interval-unknown');
131
+ }
132
+ }
133
+ function splitServiceDateTimes(serviceDateTimes) {
134
+ const flattenedMap = serviceDateTimes.reduce((acc, serviceDateTime) => {
135
+ ORDER_FORMATS.forEach(readableOrderFormat => {
136
+ if ((0, __1.isWithinFlag)(readableOrderFormat.id, serviceDateTime.orderFormats)) {
137
+ if (!acc[readableOrderFormat.id]) {
138
+ acc[readableOrderFormat.id] = {
139
+ orderFormat: readableOrderFormat,
140
+ intervals: [],
141
+ };
142
+ }
143
+ acc[readableOrderFormat.id].intervals.push(...serviceDateTime.intervals.sort((a, b) => a.dayOfWeek - b.dayOfWeek));
144
+ }
145
+ });
146
+ return acc;
147
+ }, {});
148
+ return Object.values(flattenedMap);
149
+ }
150
+ function mergeDuplicateOpeningHours(tables) {
151
+ return tables.reduce((acc, table, index) => {
152
+ const duplicateIndex = acc.findIndex((otherTable) => otherTable !== table &&
153
+ !otherTable.orderFormats.some(otherOrderFormat => table.orderFormats.some(orderFormat => orderFormat.id === otherOrderFormat.id)) &&
154
+ otherTable.openingHours.every(openingHours => table.openingHours.some(o => o.key === openingHours.key)) &&
155
+ table.openingHours.every(openingHours => otherTable.openingHours.some(o => o.key === openingHours.key)));
156
+ if (duplicateIndex >= 0) {
157
+ const duplicate = acc[duplicateIndex];
158
+ acc.splice(duplicateIndex, 1, Object.assign(Object.assign({}, duplicate), { orderFormats: [...table.orderFormats, ...duplicate.orderFormats] }));
159
+ acc.splice(index, 1);
160
+ return acc;
161
+ }
162
+ return acc;
163
+ }, [...tables]);
164
+ }
165
+ function identifyIntervals(serviceDateTimes) {
166
+ return serviceDateTimes.map(serviceDateTime => (Object.assign(Object.assign({}, serviceDateTime), { intervals: serviceDateTime.intervals.map(interval => (Object.assign(Object.assign({}, interval), { id: generateIntervalId(interval) }))) })));
167
+ }
168
+ /**
169
+ * Get an array of opening hours divided by order formats
170
+ * @param outlet Outlet from nearby endpoint
171
+ * @param nowISOString Optional ISO date string of current datetime
172
+ * @returns Opening hours table
173
+ */
174
+ function getListOutletOpeningHoursTable(outlet, nowISOString) {
175
+ // Split service date times into one array for each order format
176
+ const splittedServiceDateTimes = splitServiceDateTimes(identifyIntervals(outlet.serviceDateTimes));
177
+ // Get next 7 days including today
178
+ const generatedWeekFromToday = generateWeekFromToday(nowISOString);
179
+ // Sort days by ISO weekday (Monday first)
180
+ const sortedWeek = sortByIsoWeekday(generatedWeekFromToday);
181
+ const intervalsOrderFormatMap = splittedServiceDateTimes.reduce((acc, serviceDateTime) => {
182
+ if (!acc[serviceDateTime.orderFormat.id]) {
183
+ acc[serviceDateTime.orderFormat.id] = {};
184
+ }
185
+ serviceDateTime.intervals.reduce((intervalsAcc, interval) => {
186
+ collectReadableInterval(interval, sortedWeek, intervalsAcc);
187
+ return intervalsAcc;
188
+ }, acc[serviceDateTime.orderFormat.id]);
189
+ return acc;
190
+ }, {});
191
+ const readableOrderFormatMap = {
192
+ [__1.OrderFormat.EatIn]: ORDER_FORMATS[0],
193
+ [__1.OrderFormat.Takeaway]: ORDER_FORMATS[1],
194
+ [__1.OrderFormat.TableOrder]: ORDER_FORMATS[2],
195
+ [__1.OrderFormat.Delivery]: ORDER_FORMATS[3],
196
+ };
197
+ const openingHoursTable = Object.entries(intervalsOrderFormatMap).map(([orderFormatId, intervals]) => ({
198
+ orderFormats: [readableOrderFormatMap[Number(orderFormatId)]],
199
+ openingHours: Object.entries(intervals).map(([isoWeekday, readableInterval]) => ({
200
+ isoWeekday: Number(isoWeekday),
201
+ key: readableInterval.key,
202
+ open: readableInterval.open.sort((a, b) => a.start.localeCompare(b.start)),
203
+ adjusted: readableInterval.adjusted.sort((a, b) => a.start.localeCompare(b.start)),
204
+ closed: readableInterval.closed.sort((a, b) => a.start.localeCompare(b.start)),
205
+ })),
206
+ }));
207
+ const mergedOpeningHours = mergeDuplicateOpeningHours(openingHoursTable);
208
+ return mergedOpeningHours.sort((a, b) => a.orderFormats[0].id - b.orderFormats[0].id);
209
+ }
210
+ exports.default = getListOutletOpeningHoursTable;
@@ -0,0 +1 @@
1
+ export { default as getListOutletOpeningHoursTable } from './getListOutletOpeningHoursTable';
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getListOutletOpeningHoursTable = void 0;
7
+ var getListOutletOpeningHoursTable_1 = require("./getListOutletOpeningHoursTable");
8
+ Object.defineProperty(exports, "getListOutletOpeningHoursTable", { enumerable: true, get: function () { return __importDefault(getListOutletOpeningHoursTable_1).default; } });
@@ -0,0 +1,26 @@
1
+ import { DayOfWeek, IntervalState, IntervalType, OrderFormat } from '..';
2
+ /** HH:mm:ss */
3
+ export declare type IntervalTimestamp = string;
4
+ export declare type Interval = {
5
+ type: IntervalType;
6
+ state: IntervalState;
7
+ orderFormat: OrderFormat;
8
+ dayOfWeek: DayOfWeek;
9
+ start: IntervalTimestamp;
10
+ duration: IntervalTimestamp;
11
+ fromDate: string;
12
+ toDate: string;
13
+ reason: string;
14
+ position: number;
15
+ };
16
+ export declare type ServiceDateTime = {
17
+ orderFormats: OrderFormat;
18
+ intervals: Interval[];
19
+ isDefault: boolean;
20
+ };
21
+ export declare type ListOutlet = {
22
+ serviceDateTimes: ServiceDateTime[];
23
+ };
24
+ export declare type DetailedOutlet = {
25
+ openingHours: Interval[];
26
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,24 @@
1
+ export declare enum OrderFormat {
2
+ EatIn = 1,
3
+ Takeaway = 2,
4
+ TableOrder = 4,
5
+ Delivery = 8
6
+ }
7
+ export declare enum DayOfWeek {
8
+ Monday = 1,
9
+ Tuesday = 2,
10
+ Wednesday = 4,
11
+ Thursday = 8,
12
+ Friday = 16,
13
+ Saturday = 32,
14
+ Sunday = 64,
15
+ Everyday = 127
16
+ }
17
+ export declare enum IntervalState {
18
+ Open = 0,
19
+ Closed = 1
20
+ }
21
+ export declare enum IntervalType {
22
+ Interval = 0,
23
+ Exception = 1
24
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IntervalType = exports.IntervalState = exports.DayOfWeek = exports.OrderFormat = void 0;
4
+ var OrderFormat;
5
+ (function (OrderFormat) {
6
+ OrderFormat[OrderFormat["EatIn"] = 1] = "EatIn";
7
+ OrderFormat[OrderFormat["Takeaway"] = 2] = "Takeaway";
8
+ OrderFormat[OrderFormat["TableOrder"] = 4] = "TableOrder";
9
+ OrderFormat[OrderFormat["Delivery"] = 8] = "Delivery";
10
+ })(OrderFormat = exports.OrderFormat || (exports.OrderFormat = {}));
11
+ var DayOfWeek;
12
+ (function (DayOfWeek) {
13
+ DayOfWeek[DayOfWeek["Monday"] = 1] = "Monday";
14
+ DayOfWeek[DayOfWeek["Tuesday"] = 2] = "Tuesday";
15
+ DayOfWeek[DayOfWeek["Wednesday"] = 4] = "Wednesday";
16
+ DayOfWeek[DayOfWeek["Thursday"] = 8] = "Thursday";
17
+ DayOfWeek[DayOfWeek["Friday"] = 16] = "Friday";
18
+ DayOfWeek[DayOfWeek["Saturday"] = 32] = "Saturday";
19
+ DayOfWeek[DayOfWeek["Sunday"] = 64] = "Sunday";
20
+ DayOfWeek[DayOfWeek["Everyday"] = 127] = "Everyday";
21
+ })(DayOfWeek = exports.DayOfWeek || (exports.DayOfWeek = {}));
22
+ var IntervalState;
23
+ (function (IntervalState) {
24
+ IntervalState[IntervalState["Open"] = 0] = "Open";
25
+ IntervalState[IntervalState["Closed"] = 1] = "Closed";
26
+ })(IntervalState = exports.IntervalState || (exports.IntervalState = {}));
27
+ var IntervalType;
28
+ (function (IntervalType) {
29
+ IntervalType[IntervalType["Interval"] = 0] = "Interval";
30
+ IntervalType[IntervalType["Exception"] = 1] = "Exception";
31
+ })(IntervalType = exports.IntervalType || (exports.IntervalType = {}));
@@ -0,0 +1 @@
1
+ export default function generateId(name?: string): string;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ function generateId(name) {
4
+ const rnd = Math.random().toString();
5
+ return `${name ? `${name}-` : ''}${rnd.substring(2)}`;
6
+ }
7
+ exports.default = generateId;
@@ -0,0 +1,3 @@
1
+ export { IntervalState, DayOfWeek, IntervalType, OrderFormat } from './enums';
2
+ export { default as isWithinFlag } from './isWithinFlag';
3
+ export { default as generateId } from './generateId';
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateId = exports.isWithinFlag = exports.OrderFormat = exports.IntervalType = exports.DayOfWeek = exports.IntervalState = void 0;
7
+ var enums_1 = require("./enums");
8
+ Object.defineProperty(exports, "IntervalState", { enumerable: true, get: function () { return enums_1.IntervalState; } });
9
+ Object.defineProperty(exports, "DayOfWeek", { enumerable: true, get: function () { return enums_1.DayOfWeek; } });
10
+ Object.defineProperty(exports, "IntervalType", { enumerable: true, get: function () { return enums_1.IntervalType; } });
11
+ Object.defineProperty(exports, "OrderFormat", { enumerable: true, get: function () { return enums_1.OrderFormat; } });
12
+ var isWithinFlag_1 = require("./isWithinFlag");
13
+ Object.defineProperty(exports, "isWithinFlag", { enumerable: true, get: function () { return __importDefault(isWithinFlag_1).default; } });
14
+ var generateId_1 = require("./generateId");
15
+ Object.defineProperty(exports, "generateId", { enumerable: true, get: function () { return __importDefault(generateId_1).default; } });
@@ -0,0 +1 @@
1
+ export default function isWithinFlag(needle: number, haystack: number): boolean;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ function isWithinFlag(needle, haystack) {
4
+ return (haystack & needle) === needle;
5
+ }
6
+ exports.default = isWithinFlag;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ancon/wildcat-utils",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "",
5
5
  "repository": "git@bitbucket.org:anconab/wildcat.utils.git",
6
6
  "main": "dist/index.js",