diff --git a/packages/helpers/classes/index.js b/packages/helpers/classes/index.js index 9b4dcd169..5071b6110 100644 --- a/packages/helpers/classes/index.js +++ b/packages/helpers/classes/index.js @@ -8,6 +8,7 @@ const EmailAddress = require('./email-address'); const Mail = require('./mail'); const Personalization = require('./personalization'); const ResponseError = require('./response-error'); +const Statistics = require('./statistics'); /** * Export @@ -18,4 +19,5 @@ module.exports = { Mail, Personalization, ResponseError, + Statistics, }; diff --git a/packages/helpers/classes/statistics.d.ts b/packages/helpers/classes/statistics.d.ts new file mode 100644 index 000000000..64fe61777 --- /dev/null +++ b/packages/helpers/classes/statistics.d.ts @@ -0,0 +1,56 @@ +export class Stats { + startDate: Date; + endDate?: Date; + aggregatedBy?: string; +} + +export default class Statistics { + constructor(data?: Stats); + + fromData(data: Stats): void; + + /** + * To JSON + */ + toJSON(): Stats; + + /** + * Get Advanced Statistics + */ + getAdvanced(); + + /** + * Get Category Statistics + */ + getCategory(); + + /** + * Get Global Statistics + */ + getGlobal(); + + /** + * Get Parse Statistics + */ + getParse(); + + /** + * Get Subuser Statistics + */ + getSubuser(); + + /** + * Set StartDate + */ + setStartDate(startDate: Date): void; + + /** + * Set EndDate + */ + setEndDate(endDate: Date): void; + + /** + * Set AggregatedBy + */ + setAggregatedBy(aggregatedBy: string): void; +} \ No newline at end of file diff --git a/packages/helpers/classes/statistics.js b/packages/helpers/classes/statistics.js new file mode 100644 index 000000000..6180f949c --- /dev/null +++ b/packages/helpers/classes/statistics.js @@ -0,0 +1,284 @@ +'use strict'; + +/** + * Dependencies + */ +const toCamelCase = require('../helpers/to-camel-case'); +const deepClone = require('../helpers/deep-clone'); + +/** + * Options + */ +const AggregatedByOptions = ['day', 'week', 'month']; +const CountryOptions = ['us', 'ca']; +const SortByDirection = ['desc', 'asc']; + +/** + * Statistics class + */ +class Statistics { + constructor(data) { + this.startDate = null; + this.endDate = null; + this.aggregatedBy = null; + + if (data) { + this.fromData(data); + } + } + + /** + * Build from data + */ + fromData(data) { + + //Expecting object + if (typeof data !== 'object') { + throw new Error('Expecting object for Statistics data'); + } + + //Convert to camel case to make it workable, making a copy to prevent + //changes to the original objects + data = deepClone(data); + data = toCamelCase(data, ['substitutions', 'customArgs']); + + const { startDate, + endDate, + aggregatedBy, + } = data; + + this.setStartDate(startDate); + this.setEndDate(endDate); + this.setAggregatedBy(aggregatedBy); + } + + /** + * Set startDate + */ + setStartDate(startDate) { + if (typeof startDate === 'undefined') { + throw new Error('Date expected for `startDate`'); + } + + if ((new Date(startDate) === 'Invalid Date') || + isNaN(new Date(startDate))) { + throw new Error('Date expected for `startDate`'); + } + + console.log(startDate); + + this.startDate = new Date(startDate).toISOString().slice(0, 10); + } + + /** + * Set endDate + */ + setEndDate(endDate) { + if (typeof endDate === 'undefined') { + this.endDate = new Date().toISOString().slice(0, 10); + return; + } + + if (new Date(endDate) === 'Invalid Date' || isNaN(new Date(endDate))) { + throw new Error('Date expected for `endDate`'); + } + + this.endDate = new Date(endDate).toISOString().slice(0, 10); + } + + /** + * Set aggregatedBy + */ + setAggregatedBy(aggregatedBy) { + if (typeof aggregatedBy === 'undefined') { + return; + } + + if (typeof aggregatedBy === 'string' && + AggregatedByOptions.includes(aggregatedBy.toLowerCase())) { + this.aggregatedBy = aggregatedBy; + } + else { + throw new Error('Incorrect value for `aggregatedBy`'); + } + } + + /** + * Get Global + */ + getGlobal() { + const { startDate, endDate, aggregatedBy } = this; + + return { startDate, endDate, aggregatedBy }; + } + + /** + * Get Advanced + */ + getAdvanced(country) { + const json = this.getGlobal(); + + if (typeof country === 'undefined') { + return json; + } + + if (typeof country === 'string' && + CountryOptions.includes(country.toLowerCase())) { + json.country = country; + } + + return json; + } + + /** + * Get Advanced Mailbox Providers + */ + getAdvancedMailboxProviders(mailBoxProviders) { + const json = this.getGlobal(); + + if (typeof mailBoxProviders === 'undefined') { + return json; + } + + if (Array.isArray(mailBoxProviders) && + mailBoxProviders.some(x => typeof x !== 'string')) { + throw new Error('Array of strings expected for `mailboxProviders`'); + } + + json.mailBoxProviders = mailBoxProviders; + + return json; + } + + /** + * Get Advanced Browsers + */ + getAdvancedBrowsers(browsers) { + const json = this.getGlobal(); + + if (typeof browsers === 'undefined') { + return json; + } + + if (Array.isArray(browsers) && browsers.some(x => typeof x !== 'string')) { + throw new Error('Array of strings expected for `browsers`'); + } + + json.browsers = browsers; + + return json; + } + + /** + * Get Categories + */ + getCategories(categories) { + if (typeof categories === 'undefined') { + throw new Error('Array of strings expected for `categories`'); + } + + if (!this._isValidArrayOfStrings(categories)) { + throw new Error('Array of strings expected for `categories`'); + } + + const json = this.getGlobal(); + json.categories = categories; + + return json; + } + + /** + * Get Subuser + */ + getSubuser(subusers) { + if (typeof subusers === 'undefined') { + throw new Error('Array of strings expected for `subusers`'); + } + + if (!this._isValidArrayOfStrings(subusers)) { + throw new Error('Array of strings expected for `subusers`'); + } + + const json = this.getGlobal(); + json.subusers = subusers; + + return json; + } + + /** + * Get Subuser Sum + */ + getSubuserSum(sortByMetric = 'delivered', + sortByDirection = SortByDirection[0], limit = 5, offset = 0) { + if (typeof sortByMetric !== 'string') { + throw new Error('string expected for `sortByMetric`'); + } + + if (!SortByDirection.includes(sortByDirection.toLowerCase())) { + throw new Error('desc or asc expected for `sortByDirection`'); + } + + if (typeof limit !== 'number') { + throw new Error('number expected for `limit`'); + } + + if (typeof offset !== 'number') { + throw new Error('number expected for `offset`'); + } + + const json = this.getGlobal(); + + json.sortByMetric = sortByMetric; + json.sortByDirection = sortByDirection; + json.limit = limit; + json.offset = offset; + + return json; + } + + /** + * Get Subuser Monthly + */ + getSubuserMonthly(sortByMetric = 'delivered', + sortByDirection = SortByDirection[0], limit = 5, offset = 0) { + if (typeof sortByMetric !== 'string') { + throw new Error('string expected for `sortByMetric`'); + } + + if (!SortByDirection.includes(sortByDirection.toLowerCase())) { + throw new Error('desc or asc expected for `sortByDirection`'); + } + + if (typeof limit !== 'number') { + throw new Error('number expected for `limit`'); + } + + if (typeof offset !== 'number') { + throw new Error('number expected for `offset`'); + } + + const json = this.getGlobal(); + + json.sortByMetric = sortByMetric; + json.sortByDirection = sortByDirection; + json.limit = limit; + json.offset = offset; + + return json; + } + + _isValidArrayOfStrings(arr) { + if (!Array.isArray(arr)) { + return false; + } + + if (arr.length < 1 || arr.some(x => typeof x !== 'string')) { + return false; + } + + return true; + } +} + +//Export class +module.exports = Statistics; diff --git a/packages/helpers/classes/statistics.spec.js b/packages/helpers/classes/statistics.spec.js new file mode 100644 index 000000000..427fd4773 --- /dev/null +++ b/packages/helpers/classes/statistics.spec.js @@ -0,0 +1,192 @@ +'use strict'; + +/** + * Dependencies + */ +const Statistics = require('./statistics'); + +/** + * Tests + */ +describe('Statistics', function() { + + //Test data + const data = { + startDate: new Date(), + endDate: new Date('2017-10-21'), + aggregatedBy: 'week', + }; + + describe('setStartDate()', function() { + let stats; + + beforeEach(function() { + stats = new Statistics(data); + }); + + it('should set the startDate', function() { + stats.setStartDate(new Date('2017-10-22')); + expect(stats.startDate).equal('2017-10-22'); + }); + + it('should throw error for invalid input', function() { + expect(function() { + stats.setStartDate(''); + }).to.throw(Error); + + expect(function() { + stats.setStartDate({}); + }).to.throw(Error); + }); + + it('should throw error for no input', function() { + expect(function() { + stats.setStartDate(); + }).to.throw(Error); + }); + }); + + describe('endDate()', function() { + let stats; + + beforeEach(function() { + stats = new Statistics(data); + }); + + it('should set endDate', function() { + stats.setEndDate(new Date('2017-10-22')); + expect(stats.endDate).equal('2017-10-22'); + }); + + it('should throw error for invalid input', function() { + expect(function() { + stats.setEndDate(''); + }).to.throw(Error); + }); + }); + + describe('setAggregatedBy()', function() { + let stats; + + beforeEach(function() { + stats = new Statistics(data); + }); + + it('should set aggregatedBy', function() { + stats.setAggregatedBy('week'); + expect(stats.aggregatedBy).equal('week'); + }); + + it('should throw error for invalid input', function() { + expect(function() { + stats.setAggregatedBy(''); + }).to.throw(Error); + expect(function() { + stats.setAggregatedBy([1]); + }).to.throw(Error); + }); + }); + + describe('getAdvanced()', function() { + let stats; + + beforeEach(function() { + stats = new Statistics(data); + }); + + it('should get advanced', function() { + const advanced = stats.getAdvanced('US'); + expect(advanced.country).equal('US'); + }); + }); + + describe('getAdvancedMailboxProviders()', function() { + let stats; + + beforeEach(function() { + stats = new Statistics(data); + }); + + it('should get advanced mailbox providers', function() { + const arr = ['something']; + const advanced = stats.getAdvancedMailboxProviders(arr); + expect(advanced.mailBoxProviders).equal(arr); + }); + }); + + describe('getAdvancedBrowsers()', function() { + let stats; + + beforeEach(function() { + stats = new Statistics(data); + }); + + it('should get advanced browsers', function() { + const arr = ['something']; + const advanced = stats.getAdvancedBrowsers(arr); + expect(advanced.browsers).equal(arr); + }); + }); + + describe('getCategories()', function() { + let stats; + + beforeEach(function() { + stats = new Statistics(data); + }); + + it('should get categories', function() { + const arr = ['something']; + const categories = stats.getCategories(arr); + expect(categories.categories).equal(arr); + }); + }); + + describe('getSubuser()', function() { + let stats; + + beforeEach(function() { + stats = new Statistics(data); + }); + + it('should get subusers', function() { + const arr = ['something']; + const advanced = stats.getSubuser(arr); + expect(advanced.subusers).equal(arr); + }); + }); + + describe('getSubuserSum()', function() { + let stats; + + beforeEach(function() { + stats = new Statistics(data); + }); + + it('should get subusersum', function() { + const subuser = stats.getSubuserSum('delivered', 'asc', 10, 0); + + expect(subuser.sortByMetric).equal('delivered'); + expect(subuser.sortByDirection).equal('asc'); + expect(subuser.limit).equal(10); + expect(subuser.offset).equal(0); + }); + }); + + describe('getSubuserMonthly()', function() { + let stats; + + beforeEach(function() { + stats = new Statistics(data); + }); + + it('should get subusersmonthly', function() { + const subuser = stats.getSubuserMonthly('delivered', 'asc', 10, 0); + + expect(subuser.sortByMetric).equal('delivered'); + expect(subuser.sortByDirection).equal('asc'); + expect(subuser.limit).equal(10); + expect(subuser.offset).equal(0); + }); + }); +});