diff --git a/__tests__/__snapshots__/index.js.snap b/__tests__/__snapshots__/index.js.snap index 7048bc83..0de88643 100644 --- a/__tests__/__snapshots__/index.js.snap +++ b/__tests__/__snapshots__/index.js.snap @@ -62,8 +62,16 @@ Object { "getAllCountriesInit": [Function], "getCountriesDone": [Function], "getCountriesInit": [Function], + "getManufacturersDone": [Function], + "getManufacturersInit": [Function], + "getModelsDone": [Function], + "getModelsInit": [Function], + "getOsesDone": [Function], + "getOsesInit": [Function], "getSkillTagsDone": [Function], "getSkillTagsInit": [Function], + "getTypesDone": [Function], + "getTypesInit": [Function], }, "memberTasks": Object { "dropAll": [Function], diff --git a/__tests__/actions/__snapshots__/lookup.js.snap b/__tests__/actions/__snapshots__/lookup.js.snap index 1b96d5b6..db55f680 100644 --- a/__tests__/actions/__snapshots__/lookup.js.snap +++ b/__tests__/actions/__snapshots__/lookup.js.snap @@ -7,8 +7,16 @@ Object { "getAllCountriesInit": [Function], "getCountriesDone": [Function], "getCountriesInit": [Function], + "getManufacturersDone": [Function], + "getManufacturersInit": [Function], + "getModelsDone": [Function], + "getModelsInit": [Function], + "getOsesDone": [Function], + "getOsesInit": [Function], "getSkillTagsDone": [Function], "getSkillTagsInit": [Function], + "getTypesDone": [Function], + "getTypesInit": [Function], }, } `; diff --git a/__tests__/reducers/__snapshots__/lookup.js.snap b/__tests__/reducers/__snapshots__/lookup.js.snap index 366913f0..da1dbd8c 100644 --- a/__tests__/reducers/__snapshots__/lookup.js.snap +++ b/__tests__/reducers/__snapshots__/lookup.js.snap @@ -9,8 +9,15 @@ Object { "countryCode": "AFG", }, ], + "hasMoreModels": false, + "hasMoreOses": false, "loadingCountriesError": false, "loadingSkillTagsError": true, + "manufacturers": Array [], + "modelPage": 1, + "models": Array [], + "osPage": 1, + "oses": Array [], "skillTags": Array [ Object { "domain": "SKILLS", @@ -19,6 +26,7 @@ Object { "status": "APPROVED", }, ], + "types": Array [], } `; @@ -31,8 +39,15 @@ Object { "countryCode": "AFG", }, ], + "hasMoreModels": false, + "hasMoreOses": false, "loadingCountriesError": true, "loadingSkillTagsError": true, + "manufacturers": Array [], + "modelPage": 1, + "models": Array [], + "osPage": 1, + "oses": Array [], "skillTags": Array [ Object { "domain": "SKILLS", @@ -41,6 +56,7 @@ Object { "status": "APPROVED", }, ], + "types": Array [], } `; @@ -48,7 +64,14 @@ exports[`Default reducer Get skill tags 1`] = ` Object { "allCountries": Array [], "countries": Array [], + "hasMoreModels": false, + "hasMoreOses": false, "loadingSkillTagsError": false, + "manufacturers": Array [], + "modelPage": 1, + "models": Array [], + "osPage": 1, + "oses": Array [], "skillTags": Array [ Object { "domain": "SKILLS", @@ -57,6 +80,7 @@ Object { "status": "APPROVED", }, ], + "types": Array [], } `; @@ -64,7 +88,14 @@ exports[`Default reducer Get skill tags error 1`] = ` Object { "allCountries": Array [], "countries": Array [], + "hasMoreModels": false, + "hasMoreOses": false, "loadingSkillTagsError": true, + "manufacturers": Array [], + "modelPage": 1, + "models": Array [], + "osPage": 1, + "oses": Array [], "skillTags": Array [ Object { "domain": "SKILLS", @@ -73,6 +104,7 @@ Object { "status": "APPROVED", }, ], + "types": Array [], } `; @@ -80,7 +112,15 @@ exports[`Default reducer Initial state 1`] = ` Object { "allCountries": Array [], "countries": Array [], + "hasMoreModels": false, + "hasMoreOses": false, + "manufacturers": Array [], + "modelPage": 1, + "models": Array [], + "osPage": 1, + "oses": Array [], "skillTags": Array [], + "types": Array [], } `; @@ -93,8 +133,15 @@ Object { "countryCode": "AFG", }, ], + "hasMoreModels": false, + "hasMoreOses": false, "loadingCountriesError": false, "loadingSkillTagsError": true, + "manufacturers": Array [], + "modelPage": 1, + "models": Array [], + "osPage": 1, + "oses": Array [], "skillTags": Array [ Object { "domain": "SKILLS", @@ -103,6 +150,7 @@ Object { "status": "APPROVED", }, ], + "types": Array [], } `; @@ -115,8 +163,15 @@ Object { "countryCode": "AFG", }, ], + "hasMoreModels": false, + "hasMoreOses": false, "loadingCountriesError": true, "loadingSkillTagsError": true, + "manufacturers": Array [], + "modelPage": 1, + "models": Array [], + "osPage": 1, + "oses": Array [], "skillTags": Array [ Object { "domain": "SKILLS", @@ -125,6 +180,7 @@ Object { "status": "APPROVED", }, ], + "types": Array [], } `; @@ -132,7 +188,14 @@ exports[`Factory without server side rendering Get skill tags 1`] = ` Object { "allCountries": Array [], "countries": Array [], + "hasMoreModels": false, + "hasMoreOses": false, "loadingSkillTagsError": false, + "manufacturers": Array [], + "modelPage": 1, + "models": Array [], + "osPage": 1, + "oses": Array [], "skillTags": Array [ Object { "domain": "SKILLS", @@ -141,6 +204,7 @@ Object { "status": "APPROVED", }, ], + "types": Array [], } `; @@ -148,7 +212,14 @@ exports[`Factory without server side rendering Get skill tags error 1`] = ` Object { "allCountries": Array [], "countries": Array [], + "hasMoreModels": false, + "hasMoreOses": false, "loadingSkillTagsError": true, + "manufacturers": Array [], + "modelPage": 1, + "models": Array [], + "osPage": 1, + "oses": Array [], "skillTags": Array [ Object { "domain": "SKILLS", @@ -157,6 +228,7 @@ Object { "status": "APPROVED", }, ], + "types": Array [], } `; @@ -164,6 +236,14 @@ exports[`Factory without server side rendering Initial state 1`] = ` Object { "allCountries": Array [], "countries": Array [], + "hasMoreModels": false, + "hasMoreOses": false, + "manufacturers": Array [], + "modelPage": 1, + "models": Array [], + "osPage": 1, + "oses": Array [], "skillTags": Array [], + "types": Array [], } `; diff --git a/src/actions/lookup.js b/src/actions/lookup.js index 350f2267..8ef6fd5a 100644 --- a/src/actions/lookup.js +++ b/src/actions/lookup.js @@ -6,6 +6,98 @@ import { createActions } from 'redux-actions'; import { getService } from '../services/lookup'; +/* + * device api PAGE_SIZE + */ +export const PAGE_SIZE = 100; + +/** + * @static + * @desc Creates an action that signals beginning of getting all deveice types + * @return {Action} + */ +function getTypesInit() {} + +/** + * @static + * @desc Creates an action that get all deveice types + * @return {Action} + */ +function getTypesDone() { + return getService().getTypes(); +} + + +/** + * @static + * @desc Creates an action that signals beginning of getting all manufacturers + * @return {Action} + */ +function getManufacturersInit() {} + +/** + * @static + * @desc Creates an action that get all deveice manufacturers + * @param {String} type + * @return {Action} + */ +function getManufacturersDone(type) { + return getService().getManufacturers(type); +} + + +/** + * @static + * @desc Creates an action that signals beginning of getting models + * @param {Number} page + * @return {Action} + */ +function getModelsInit(page) { + return { + page, + }; +} + +/** + * @static + * @desc Creates an action that get all deveice models + * @param {Number} page + * @param {String} manufacturer + * @param {String} type + * @return {Action} + */ +function getModelsDone(page, type, manufacturer) { + return getService().getDevices(page, PAGE_SIZE, type, manufacturer); +} + + +/** + * @static + * @desc Creates an action that signals beginning of getting operation systems + * + * @param {Number} page + * @return {Action} + */ +function getOsesInit(page) { + return { + page, + }; +} + +/** + * @static + * @desc Creates an action that get all operation systems + * @param {Number} page + * @param {String} manufacturer + * @param {String} type + * @param {String} model + * @return {Action} + */ +function getOsesDone(page, type, manufacturer, model) { + return getService().getDevices(page, PAGE_SIZE, type, manufacturer, model); +} + + /** * @static * @desc Creates an action that signals beginning of getting all skill tags. @@ -61,6 +153,14 @@ function getAllCountriesDone(tokenV3) { export default createActions({ LOOKUP: { + GET_TYPES_INIT: getTypesInit, + GET_TYPES_DONE: getTypesDone, + GET_MANUFACTURERS_INIT: getManufacturersInit, + GET_MANUFACTURERS_DONE: getManufacturersDone, + GET_MODELS_INIT: getModelsInit, + GET_MODELS_DONE: getModelsDone, + GET_OSES_INIT: getOsesInit, + GET_OSES_DONE: getOsesDone, GET_SKILL_TAGS_INIT: getSkillTagsInit, GET_SKILL_TAGS_DONE: getSkillTagsDone, GET_COUNTRIES_INIT: getCountriesInit, diff --git a/src/reducers/lookup.js b/src/reducers/lookup.js index a8e0670e..94b66f21 100644 --- a/src/reducers/lookup.js +++ b/src/reducers/lookup.js @@ -8,7 +8,155 @@ import _ from 'lodash'; import { handleActions } from 'redux-actions'; import logger from '../utils/logger'; -import actions from '../actions/lookup'; +import actions, { PAGE_SIZE } from '../actions/lookup'; + + +/** + * Handles LOOKUP/GET_TYPES_DONE action. + * @param {Object} state + * @param {Object} action Payload will be JSON from api call + * @return {Object} New state + */ +function onGetTypesDone(state, { payload, error }) { + if (error) { + logger.error('Failed to get types', payload); + return { ...state, loadingTypesError: true }; + } + + const types = _.map(_.uniq(payload.sort()), v => ({ + key: v, + name: v, + })); + return ({ + ...state, + loadingTypesError: false, + types, + }); +} + + +/** + * Handles LOOKUP/GET_MANUFACTURERS_INIT action. + * @param {Object} state + * @param {Object} action Payload will be JSON from api call + * @return {Object} New state + */ +function onGetManufacturersInit(state) { + return { + ...state, manufacturers: [], models: [], oses: [], + }; +} + +/** + * Handles LOOKUP/GET_MANUFACTURERS_DONE action. + * @param {Object} state + * @param {Object} action Payload will be JSON from api call + * @return {Object} New state + */ +function onGetManufacturersDone(state, { payload, error }) { + if (error) { + logger.error('Failed to get types', payload); + return { ...state, loadingManufacturersError: true }; + } + + const manufacturers = _.map(_.uniq(payload.sort()), v => ({ + key: v, + name: v, + })); + return ({ + ...state, + loadingManufacturersError: false, + manufacturers, + }); +} + + +/** + * Handles LOOKUP/GET_MODELS_INIT action. + * @param {Object} state + * @param {Object} action Payload will be JSON from api call + * @return {Object} New state + */ +function onGetModelsInit(state, { payload }) { + // if load more, don't clear state + if (payload.page > 1) { + return { ...state, modelPage: payload.page, isModelsLoading: true }; + } + return { + ...state, models: [], oses: [], modelPage: payload.page, isModelsLoading: true, + }; +} + +/** + * Handles LOOKUP/GET_MODELS_DONE action. + * @param {Object} state + * @param {Object} action Payload will be JSON from api call + * @return {Object} New state + */ +function onGetModelsDone(state, { payload, error }) { + if (error) { + logger.error('Failed to get types', payload); + return { ...state, loadingModelsError: true, isModelsLoading: false }; + } + + let models = payload; + + if (state.modelPage > 1) { + models = [...state.models, ...models]; + } + models = _.orderBy(models, ['model'], ['asc']); + models = _.uniqBy(models, m => m.name); + + return ({ + ...state, + loadingModelsError: false, + models, + hasMoreModels: models.length === PAGE_SIZE, + isModelsLoading: false, + }); +} + +/** + * Handles LOOKUP/GET_OSES_INIT action. + * @param {Object} state + * @param {Object} action Payload will be JSON from api call + * @return {Object} New state + */ +function onGetOsesInit(state, { payload }) { + return { + ...state, osPage: payload.page, isOsesLoading: true, + }; +} + + +/** + * Handles LOOKUP/GET_OSES_DONE action. + * @param {Object} state + * @param {Object} action Payload will be JSON from api call + * @return {Object} New state + */ +function onGetOsesDone(state, { payload, error }) { + if (error) { + logger.error('Failed to get types', payload); + return { ...state, loadingOsesError: true, isOsesLoading: false }; + } + + let oses = payload; + if (state.osPage > 1) { + oses = [...state.oses, ...oses]; + } + oses = _.orderBy(payload, ['operatingSystem'], ['asc']); + + oses = _.uniqBy(oses, m => m.name); + return ({ + ...state, + loadingOsesError: false, + oses, + hasMoreOses: oses.length === PAGE_SIZE, + isOsesLoading: false, + }); +} + /** * Handles LOOKUP/GET_SKILL_TAGS_DONE action. @@ -75,6 +223,14 @@ function onGetAllCountriesDone(state, { payload, error }) { function create(initialState = {}) { const a = actions.lookup; return handleActions({ + [a.getTypesInit]: state => state, + [a.getTypesDone]: onGetTypesDone, + [a.getManufacturersInit]: onGetManufacturersInit, + [a.getManufacturersDone]: onGetManufacturersDone, + [a.getModelsInit]: onGetModelsInit, + [a.getModelsDone]: onGetModelsDone, + [a.getOsesInit]: onGetOsesInit, + [a.getOsesDone]: onGetOsesDone, [a.getSkillTagsInit]: state => state, [a.getSkillTagsDone]: onGetSkillTagsDone, [a.getCountriesInit]: state => state, @@ -85,6 +241,14 @@ function create(initialState = {}) { skillTags: [], countries: [], allCountries: [], + types: [], + manufacturers: [], + models: [], + modelPage: 1, + hasMoreModels: false, + oses: [], + osPage: 1, + hasMoreOses: false, })); } diff --git a/src/services/lookup.js b/src/services/lookup.js index 8c6595a9..9710882e 100644 --- a/src/services/lookup.js +++ b/src/services/lookup.js @@ -4,6 +4,7 @@ * via API V3. */ import qs from 'qs'; +import { assign } from 'lodash'; import { getApiResponsePayload } from '../utils/tc'; import { getApi } from './api'; @@ -19,6 +20,63 @@ class LookupService { }; } + /** + * Gets types + * @return {Promise} Resolves to the types + */ + async getTypes() { + try { + const res = await this.private.apiV5.get('/lookups/devices/types'); + return res.json(); + } catch (e) { + throw e; + } + } + + /** + * Gets Manufacturers. + * @param {String} params type + * @return {Promise} Resolves to the getManufacturers. + */ + async getManufacturers(type) { + const params = { + type, + }; + + try { + const res = await this.private.apiV5.get(`/lookups/devices/manufacturers?${qs.stringify(params)}`); + return res.json(); + } catch (e) { + throw e; + } + } + + /** + * Gets Devices + * @param {number} page + * @param {Number} pageSize + * @param {String} type + * @param {String} manufacturer + * @param {String} model + * @return {Promise} Resolves to the Devices. + */ + async getDevices(page = 1, pageSize, type, manufacturer, model) { + const params = { + perPage: pageSize, + }; + assign(params, { + type, manufacturer, model, page, + }); + + try { + const res = await this.private.apiV5.get(`/lookups/devices?${qs.stringify(params)}`); + return res.json(); + } catch (e) { + throw e; + } + } + + /** * Gets tags. * @param {Object} params Parameters