@justeattakeaway/cc-filters
Version:
Filter function for content card loader
137 lines (126 loc) • 5.49 kB
JavaScript
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