diff --git a/frontend/src/__mocks__/react-mdl.js b/frontend/src/__mocks__/react-mdl.js index 2deaebe0e0..04e07f153d 100644 --- a/frontend/src/__mocks__/react-mdl.js +++ b/frontend/src/__mocks__/react-mdl.js @@ -17,4 +17,6 @@ module.exports = { Tabs: 'react-mdl-Tabs', TableHeader: 'react-mdl-TableHeader', Textfield: 'react-mdl-Textfield', + FooterSection: 'react-mdl-FooterSection', + FooterLinkList: 'react-mdl-FooterLinkList', }; diff --git a/frontend/src/component/api/__tests__/.eslintrc b/frontend/src/component/api/__tests__/.eslintrc new file mode 100644 index 0000000000..eba2077219 --- /dev/null +++ b/frontend/src/component/api/__tests__/.eslintrc @@ -0,0 +1,5 @@ +{ + "env": { + "jest": true + } +} diff --git a/frontend/src/component/api/__tests__/__snapshots__/show-api-details-component-test.jsx.snap b/frontend/src/component/api/__tests__/__snapshots__/show-api-details-component-test.jsx.snap new file mode 100644 index 0000000000..3bfed09ff5 --- /dev/null +++ b/frontend/src/component/api/__tests__/__snapshots__/show-api-details-component-test.jsx.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly with details 1`] = ` + + + + GitHub + + + + A product by + + FINN.no + + + +`; + +exports[`renders correctly with empty api details 1`] = ` + + + + GitHub + + + + A product by + + FINN.no + + + +`; diff --git a/frontend/src/component/api/__tests__/show-api-details-component-test.jsx b/frontend/src/component/api/__tests__/show-api-details-component-test.jsx new file mode 100644 index 0000000000..c712fff910 --- /dev/null +++ b/frontend/src/component/api/__tests__/show-api-details-component-test.jsx @@ -0,0 +1,18 @@ +import React from 'react'; + +import ShowApiDetailsComponent from '../show-api-details-component'; +import renderer from 'react-test-renderer'; + +jest.mock('react-mdl'); + +test('renders correctly with empty api details', () => { + const tree = renderer.create().toJSON(); + expect(tree).toMatchSnapshot(); +}); + +test('renders correctly with details', () => { + const tree = renderer + .create() + .toJSON(); + expect(tree).toMatchSnapshot(); +}); diff --git a/frontend/src/component/api/show-api-details-component.jsx b/frontend/src/component/api/show-api-details-component.jsx new file mode 100644 index 0000000000..c0c83a42ec --- /dev/null +++ b/frontend/src/component/api/show-api-details-component.jsx @@ -0,0 +1,32 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { FooterSection, FooterLinkList } from 'react-mdl'; + +class ShowApiDetailsComponent extends Component { + static propTypes = { + apiDetails: PropTypes.object.isRequired, + fetchAll: PropTypes.func.isRequired, + }; + + componentDidMount() { + this.props.fetchAll(); + } + + render() { + const version = this.props.apiDetails.version || ''; + return ( + + + + GitHub + + + A product by FINN.no + + + + ); + } +} + +export default ShowApiDetailsComponent; diff --git a/frontend/src/component/api/show-api-details-container.jsx b/frontend/src/component/api/show-api-details-container.jsx new file mode 100644 index 0000000000..fccb7319ef --- /dev/null +++ b/frontend/src/component/api/show-api-details-container.jsx @@ -0,0 +1,13 @@ +import { connect } from 'react-redux'; +import ShowApiDetailsComponent from './show-api-details-component'; +import { fetchAll } from '../../store/api/actions'; + +const mapDispatchToProps = { + fetchAll, +}; + +const mapStateToProps = state => ({ + apiDetails: state.api.toJS(), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(ShowApiDetailsComponent); diff --git a/frontend/src/component/app.jsx b/frontend/src/component/app.jsx index f252587ff8..a573d253d2 100644 --- a/frontend/src/component/app.jsx +++ b/frontend/src/component/app.jsx @@ -20,6 +20,7 @@ import ErrorContainer from './error/error-container'; import UserContainer from './user/user-container'; import ShowUserContainer from './user/show-user-container'; +import ShowApiDetailsContainer from './api/show-api-details-container'; import { ScrollContainer } from 'react-router-scroll'; function replace(input, params) { @@ -193,16 +194,7 @@ export default class App extends Component { - - - - GitHub - - - A product by FINN.no - - - + diff --git a/frontend/src/data/api.js b/frontend/src/data/api.js new file mode 100644 index 0000000000..e584f14407 --- /dev/null +++ b/frontend/src/data/api.js @@ -0,0 +1,13 @@ +import { throwIfNotSuccess, headers } from './helper'; + +const URI = 'api'; + +function fetchAll() { + return fetch(URI, { headers, credentials: 'include' }) + .then(throwIfNotSuccess) + .then(response => response.json()); +} + +export default { + fetchAll, +}; diff --git a/frontend/src/store/api/__tests__/.eslintrc b/frontend/src/store/api/__tests__/.eslintrc new file mode 100644 index 0000000000..eba2077219 --- /dev/null +++ b/frontend/src/store/api/__tests__/.eslintrc @@ -0,0 +1,5 @@ +{ + "env": { + "jest": true + } +} diff --git a/frontend/src/store/api/__tests__/api-store-tests.js b/frontend/src/store/api/__tests__/api-store-tests.js new file mode 100644 index 0000000000..93140f8d2d --- /dev/null +++ b/frontend/src/store/api/__tests__/api-store-tests.js @@ -0,0 +1,18 @@ +import apiReducer from '../index'; +import { RECIEVE_API_DETAILS } from '../actions'; + +test('should have inital state', () => { + const store = apiReducer(undefined, {}); + expect(store.toJS()).toEqual({}); +}); + +test('should have new state', () => { + const store = apiReducer(undefined, { type: RECIEVE_API_DETAILS, value: { version: '1.1.1' } }); + expect(store.toJS()).toEqual({ version: '1.1.1' }); +}); + +test('should have updated state', () => { + const inital = apiReducer(undefined, { type: RECIEVE_API_DETAILS, value: { version: '1.1.1' } }); + const store = apiReducer(inital, { type: RECIEVE_API_DETAILS, value: { version: '1.2.1' } }); + expect(store.toJS()).toEqual({ version: '1.2.1' }); +}); diff --git a/frontend/src/store/api/actions.js b/frontend/src/store/api/actions.js new file mode 100644 index 0000000000..a8ef51b855 --- /dev/null +++ b/frontend/src/store/api/actions.js @@ -0,0 +1,24 @@ +import api from '../../data/api'; + +export const RECIEVE_API_DETAILS = 'RECIEVE_API_DETAILS'; +export const ERROR_RECIEVE_API_DETAILS = 'ERROR_RECIEVE_API_DETAILS'; + +export const RECEIVE_APPLICATION = 'RECEIVE_APPLICATION'; + +const recieveApiDetails = json => ({ + type: RECIEVE_API_DETAILS, + value: json, +}); + +const errorRecieveApiDetails = (statusCode, type = ERROR_RECIEVE_API_DETAILS) => ({ + type, + statusCode, +}); + +export function fetchAll() { + return dispatch => + api + .fetchAll() + .then(json => dispatch(recieveApiDetails(json))) + .catch(error => dispatch(errorRecieveApiDetails(error))); +} diff --git a/frontend/src/store/api/index.js b/frontend/src/store/api/index.js new file mode 100644 index 0000000000..756b8b4688 --- /dev/null +++ b/frontend/src/store/api/index.js @@ -0,0 +1,14 @@ +import { Map } from 'immutable'; +import { RECIEVE_API_DETAILS } from './actions'; + +const store = (state = new Map(), action) => { + switch (action.type) { + case RECIEVE_API_DETAILS: + state = new Map(action.value); + return state; + default: + return state; + } +}; + +export default store; diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js index 0ca4a4b88f..278cea3ab9 100644 --- a/frontend/src/store/index.js +++ b/frontend/src/store/index.js @@ -9,6 +9,7 @@ import error from './error-store'; import clientInstances from './client-instance-store'; import settings from './settings'; import user from './user'; +import api from './api'; import applications from './application'; const unleashStore = combineReducers({ @@ -23,6 +24,7 @@ const unleashStore = combineReducers({ settings, user, applications, + api, }); export default unleashStore;