UNPKG

@justeattakeaway/cc-filters

Version:

Filter function for content card loader

137 lines (126 loc) 5.49 kB
import { parse, isAfter, isBefore, format } from 'date-fns'; import { orderBy, findIndex } from 'lodash-es'; const filterByBrands = (cards, brands) => cards.filter(({ brand }) => { if (brands.length > 0) { return !brand || brands.includes(brand); } return true; }); // @ts-ignore /** * Determines whether the current time is within the display times JSON * @param displayTimes * @return {boolean|boolean} */ function isCardActiveBasedOnTime(displayTimes) { const now = new Date(); const currentDay = format(now, "E"); const times = displayTimes[currentDay] || displayTimes.Any || []; return (!(times instanceof Array) || times.length === 0 || times.some(({ Start: start, End: end }) => { if (!start || !end) return true; const startTime = parse(start, "HH:mm", now); const endTime = parse(end, "HH:mm", now); return isAfter(now, startTime) && isBefore(now, endTime); })); } /** * Can be used in isolation or as part of Array.filter * @param card {object} * @param card.displayTimes {object} - Display times * @param card.isVisible {string} - Visibility indicator * @returns {boolean} - is card active */ const isCardCurrentlyActive = (card) => { const { displayTimes, isVisible } = card; return (isVisible !== false && (!displayTimes || isCardActiveBasedOnTime(displayTimes))); }; const filterByCurrentlyActive = (cards) => cards .filter(card => isCardCurrentlyActive(card)); const filterByEnabledCardTypes = (cards, enabledCardTypes) => cards .filter(({ type }) => { if (enabledCardTypes.length > 0) { return type && enabledCardTypes.includes(type); } return true; }); /** * Tests if passed lat long are valid * @param lat * @param lon * @returns {boolean} */ const hasValidLocation = (lat, lon) => { const regexExp = /^((-?|\+?)?\d+(\.\d+)?),\s*((-?|\+?)?\d+(\.\d+)?)$/gi; return regexExp.test(`${lat},${lon}`) && parseFloat(lat) !== 0 && parseFloat(lon) !== 0; }; /** * match location against ones in list * @param location * @param locationsList * @returns {boolean} */ const matchLocation = (location, locationsList) => { const locationToMatch = location.toLowerCase().replace(/\s/g, ''); const matchedLocations = locationsList.map(l => l.toLowerCase().replace(/\s/g, '')) .filter(l => locationToMatch === l).length; return matchedLocations > 0; }; /** * @param cards * @param currentLocation * @returns Array */ const locationFilter = (cards, { location, latitude, longitude }) => cards.filter(card => { var _a, _b, _c, _d; const needsLocation = (_a = card === null || card === void 0 ? void 0 : card.url) === null || _a === void 0 ? void 0 : _a.includes('$LOCATION$'); const needsLatitude = (_b = card === null || card === void 0 ? void 0 : card.url) === null || _b === void 0 ? void 0 : _b.includes('$LAT$'); const needsLongitude = (_c = card === null || card === void 0 ? void 0 : card.url) === null || _c === void 0 ? void 0 : _c.includes('$LON$'); const hasPlaceHolder = needsLongitude || needsLatitude || needsLocation; // will be undefined if no locations KVP exists const locationsList = (_d = card === null || card === void 0 ? void 0 : card.location) === null || _d === void 0 ? void 0 : _d.split(','); // return true if NO KVP and if user has no location and hasPlaceholder is false or user has location and hasPlaceholder is true if (locationsList === undefined) { return !!(!hasPlaceHolder || ((needsLocation && location)) || ((needsLongitude || needsLatitude) && hasValidLocation(latitude, longitude))); } if (hasPlaceHolder) { // if we don't have a valid lat long throw it out if ((needsLongitude || needsLatitude) && !hasValidLocation(latitude, longitude)) { return false; } // if we have a location attribute and a LOCATION placeholder with // NO current location return false if (!location) { return !needsLocation; } } else if (!location) { return true; } // match the location and return based on this return matchLocation(location, locationsList); }); const removeDuplicateContentCards = (cards) => orderBy(cards, ['updated'], ['desc']) .filter((contentCard, index, cardsList) => index === findIndex(cardsList, contentCard.deduplicationKey ? card => card.deduplicationKey === contentCard.deduplicationKey : card => !card.deduplicationKey && card.title === contentCard.title && card.type === contentCard.type)); const DEFAULT_ORDER_VALUE = 9e9; const sortByCardOrder = (cards) => cards.sort(({ order: a = DEFAULT_ORDER_VALUE }, { order: b = DEFAULT_ORDER_VALUE }) => (+a - +b)); const urlLocationSubstitution = (cards, { location, longitude, latitude }) => cards.map(card => { var _a; return ({ ...card, url: (_a = card === null || card === void 0 ? void 0 : card.url) === null || _a === void 0 ? void 0 : _a.replace("$LOCATION$", location).replace("$LAT$", latitude).replace("$LON$", longitude) }); }); // @ts-ignore const pipe = (...fns) => (x) => fns.reduceRight((y, f) => f(y), x); export { filterByBrands, filterByCurrentlyActive, filterByEnabledCardTypes, locationFilter, pipe, removeDuplicateContentCards, sortByCardOrder, urlLocationSubstitution }; //# sourceMappingURL=index.js.map