diff --git a/mock-responses/recognitions/get_api_call_failure_response.json b/mock-responses/recognitions/get_api_call_failure_response.json new file mode 100644 index 000000000..1bd1c22b5 --- /dev/null +++ b/mock-responses/recognitions/get_api_call_failure_response.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "invalid_token", + "message": "unauthorized user" + } +} diff --git a/mock-responses/recognitions/get_api_call_success_response.json b/mock-responses/recognitions/get_api_call_success_response.json new file mode 100644 index 000000000..10a860750 --- /dev/null +++ b/mock-responses/recognitions/get_api_call_success_response.json @@ -0,0 +1,54 @@ +{ + "data": [ + { + "id": 1, + "core_value_id": 2, + "text": "good work", + "given_for": 4, + "given_by": 6, + "given_at": "1588924868", + "givenFor": { + "id": 4, + "first_name": "Avinash", + "last_name": "mane", + "profile_image_url": null + }, + "givenBy": { + "id": 6, + "first_name": "Avinash", + "last_name": "mane", + "profile_image_url": null + }, + "core_value": { + "id": 2, + "text": "good work", + "description": "good working in peerly" + } + }, + { + "id": 2, + "core_value_id": 2, + "text": "good work", + "given_for": 4, + "given_by": 6, + "given_at": "1588924868", + "givenFor": { + "id": 4, + "first_name": "Avinash", + "last_name": "mane", + "profile_image_url": null + }, + "givenBy": { + "id": 6, + "first_name": "Avinash", + "last_name": "mane", + "profile_image_url": null + }, + "core_value": { + "id": 2, + "text": "good work", + "description": "good working in peerly" + } + } + ] +} diff --git a/react-frontend/src/actions/listRecognitionAction.js b/react-frontend/src/actions/listRecognitionAction.js new file mode 100644 index 000000000..68f5e3036 --- /dev/null +++ b/react-frontend/src/actions/listRecognitionAction.js @@ -0,0 +1,6 @@ +export default (type, payload) => { + return { + type: type, + payload: payload, + }; +}; diff --git a/react-frontend/src/constants/actionConstants.js b/react-frontend/src/constants/actionConstants.js new file mode 100644 index 000000000..0d26f856f --- /dev/null +++ b/react-frontend/src/constants/actionConstants.js @@ -0,0 +1,3 @@ +export const LIST_RECOGNITION = "LIST_RECOGNITION"; + +export const LIST_RECOGNITION_API = "LIST_RECOGNITION_API"; diff --git a/react-frontend/src/recognition-list/RecognitionListContainer.js b/react-frontend/src/recognition-list/RecognitionListContainer.js new file mode 100644 index 000000000..478b0cbc2 --- /dev/null +++ b/react-frontend/src/recognition-list/RecognitionListContainer.js @@ -0,0 +1,34 @@ +import React, { useEffect } from "react"; +import { useSelector, useDispatch } from "react-redux"; + +import SessionTimeoutComponent from "shared-components/SessionTimeoutComponent"; +import UnauthorisedErrorComponent from "shared-components/UnauthorisedErrorComponent"; +import actionObjectGenrator from "actions/listRecognitionAction"; +import actionGenrator from "utils/actionGenerator"; +import { LIST_RECOGNITION_API } from "constants/actionConstants"; + +const RecognnitionListContainer = () => { + const recognitionList = useSelector((state) => state.listRecognitionReducer); + const dispatch = useDispatch(); + const status = actionGenrator(LIST_RECOGNITION_API); + + useEffect(() => { + dispatch(actionObjectGenrator(status.success)); + }, [dispatch, status.success]); + + if (recognitionList.error.code === "invalid_token") { + return ; + } else if (recognitionList.error.code === "access_denied") { + return ; + } + + return ( +
+ {recognitionList.list.map((el, key) => ( +

{el.text}

+ ))} +
+ ); +}; + +export default RecognnitionListContainer; diff --git a/react-frontend/src/reducers/listRecognitionReducer.js b/react-frontend/src/reducers/listRecognitionReducer.js new file mode 100644 index 000000000..a8153c679 --- /dev/null +++ b/react-frontend/src/reducers/listRecognitionReducer.js @@ -0,0 +1,26 @@ +import actionGenerator from "utils/actionGenerator"; + +export const defaultState = { + list: [ + { + core_value: {}, + givenFor: {}, + givenBy: {}, + }, + ], + error: { + fields: {}, + }, +}; +const status = actionGenerator("LIST_RECOGNITION"); + +export default (state = defaultState, action) => { + switch (action.type) { + case status.success: + return { ...state, list: action.payload }; + case status.failure: + return { ...state, error: action.payload }; + default: + return state; + } +}; diff --git a/react-frontend/src/reducers/listRecognitionReducer.test.js b/react-frontend/src/reducers/listRecognitionReducer.test.js new file mode 100644 index 000000000..560b94198 --- /dev/null +++ b/react-frontend/src/reducers/listRecognitionReducer.test.js @@ -0,0 +1,52 @@ +import reducer, { defaultState } from "reducers/listRecognitionReducer"; +import actionGenerator from "utils/actionGenerator"; +import actionObjectGenerator from "actions/listRecognitionAction"; + +describe("list recognition reducer", () => { + const status = actionGenerator("LIST_RECOGNITION"); + + it("list recognition reducer should return the initial state", () => { + expect(reducer(defaultState, {})).toEqual({ + list: [ + { + core_value: {}, + givenFor: {}, + givenBy: {}, + }, + ], + error: { + fields: {}, + }, + }); + }); + + it("list recognition reducer should handle success action", () => { + let reducerData = reducer( + defaultState, + actionObjectGenerator(status.success, [{ id: 1 }]) + ); + expect(reducerData).toEqual({ + list: [{ id: 1 }], + error: { + fields: {}, + }, + }); + }); + + it("list recognition reducer should handle failure action", () => { + let reducerData = reducer( + defaultState, + actionObjectGenerator(status.failure, { code: "invalid token" }) + ); + expect(reducerData).toEqual({ + list: [ + { + core_value: {}, + givenFor: {}, + givenBy: {}, + }, + ], + error: { code: "invalid token" }, + }); + }); +}); diff --git a/react-frontend/src/reducers/rootReducer.js b/react-frontend/src/reducers/rootReducer.js index 007b7e21d..fad9cda06 100644 --- a/react-frontend/src/reducers/rootReducer.js +++ b/react-frontend/src/reducers/rootReducer.js @@ -1,7 +1,9 @@ import { combineReducers } from "redux"; import appReducer from "reducers/appReducer.js"; +import listRecognitionReducer from "reducers/listRecognitionReducer"; export default combineReducers({ appReducer, + listRecognitionReducer, }); diff --git a/react-frontend/src/sagas/recognitionSaga.js b/react-frontend/src/sagas/recognitionSaga.js new file mode 100644 index 000000000..d1f35bbee --- /dev/null +++ b/react-frontend/src/sagas/recognitionSaga.js @@ -0,0 +1,36 @@ +import { put, takeEvery, spawn, call } from "redux-saga/effects"; + +import getJson from "utils/getJson"; +import actionObjectGenerator from "actions/listRecognitionAction"; +import actionGenerator from "utils/actionGenerator"; +import { + LIST_RECOGNITION, + LIST_RECOGNITION_API, +} from "constants/actionConstants"; + +export function* getRecognitionList() { + const status = actionGenerator(LIST_RECOGNITION); + try { + const response = yield call(getJson, { + path: "recognitions", + apiToken: "", + }); + const responseObj = yield response.json(); + if (responseObj.data) { + yield put(actionObjectGenerator(status.success, responseObj.data)); + } else { + yield put(actionObjectGenerator(status.failure, responseObj.error)); + } + } catch (error) { + yield put(actionObjectGenerator(status.failure, error)); + } +} + +export function* recognitionApi() { + const status = actionGenerator(LIST_RECOGNITION_API); + yield takeEvery(status.success, getRecognitionList); +} + +export default function* rootRecognitionSaga() { + yield spawn(recognitionApi); +} diff --git a/react-frontend/src/sagas/recognitionSaga.test.js b/react-frontend/src/sagas/recognitionSaga.test.js new file mode 100644 index 000000000..a96b35801 --- /dev/null +++ b/react-frontend/src/sagas/recognitionSaga.test.js @@ -0,0 +1,60 @@ +import { takeEvery, call, put } from "redux-saga/effects"; + +import { recognitionApi, getRecognitionList } from "sagas/recognitionSaga"; +import getJson from "utils/getJson"; +import actionGenerator from "utils/actionGenerator"; +import success_mockResponse from "../../../mock-responses/recognitions/get_api_call_success_response.json"; +import failure_mockResponse from "../../../mock-responses/recognitions/get_api_call_failure_response.json"; +import { + LIST_RECOGNITION_API, + LIST_RECOGNITION, +} from "constants/actionConstants.js"; +import actionObjectGenerator from "actions/listRecognitionAction"; + +describe("RECOGNITION SAGAS", () => { + const status = actionGenerator(LIST_RECOGNITION); + const apiStatus = actionGenerator(LIST_RECOGNITION_API); + const response = { json: () => "success" }; + + it("should dispatch action 'LIST_RECOGNITION_API' for recognition saga", () => { + const generator = recognitionApi(); + expect(generator.next().value).toEqual( + takeEvery(apiStatus.success, getRecognitionList) + ); + const status = generator.next().done; + expect(status).toEqual(true); + }); + + it("should dispatch action 'LIST_RECOGNITION_API' for fetch list with 200 status", () => { + const generator = getRecognitionList(); + const callFunctionDefination = generator.next().value; + + expect(callFunctionDefination).toEqual( + call(getJson, { + path: "recognitions", + apiToken: "", + }) + ); + generator.next(response).value; + expect(generator.next(success_mockResponse).value).toEqual( + put(actionObjectGenerator(status.success, success_mockResponse.data)) + ); + expect(generator.next().done).toEqual(true); + }); + + it("should dispatch action 'LIST_RECOGNITION_API' for fetch list with 401 error response", () => { + const generator = getRecognitionList(); + const callFunctionDefination = generator.next().value; + expect(callFunctionDefination).toEqual( + call(getJson, { + path: "recognitions", + apiToken: "", + }) + ); + expect(generator.next(response).value).toEqual("success"); + expect(generator.next(failure_mockResponse).value).toEqual( + put(actionObjectGenerator(status.failure, failure_mockResponse.error)) + ); + expect(generator.next().done).toEqual(true); + }); +}); diff --git a/react-frontend/src/sagas/rootSaga.js b/react-frontend/src/sagas/rootSaga.js index c56c1033b..ec894aa92 100644 --- a/react-frontend/src/sagas/rootSaga.js +++ b/react-frontend/src/sagas/rootSaga.js @@ -1,4 +1,5 @@ import { spawn } from "redux-saga/effects"; +import recognitionSaga from "sagas/recognitionSaga"; export function* helloSaga() { const msg = yield "Hello Sagas!"; @@ -8,4 +9,5 @@ export function* helloSaga() { export default function* rootSaga() { yield spawn(helloSaga); + yield spawn(recognitionSaga); }