Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JITMs: add redux structure and REST API client method to be used by the JITM component of the Jetpack Dashboard (Spin-off of #10759). #10818

Merged
merged 6 commits into from
Dec 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions _inc/client/rest-api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require( 'es6-promise' ).polyfill();
import 'whatwg-fetch';
import assign from 'lodash/assign';
import head from 'lodash/head';

/**
* Helps create new custom error classes to better notify upper layers.
Expand Down Expand Up @@ -266,8 +267,27 @@ function JetpackRestApiClient( root, nonce ) {
verifySiteGoogle: ( keyringId ) => postRequest( `${ apiRoot }jetpack/v4/verify-site/google`, postParams, {
body: JSON.stringify( { keyring_id: keyringId } ),
} )
.then( checkStatus )
.then( parseJsonResponse )
.then( checkStatus )
.then( parseJsonResponse ),

fetchJitm: ( message_path, query_url ) => {
const requestUrl = `${ apiRoot }jetpack/v4/jitm?message_path=${ encodeURIComponent( message_path ) }&query=${ encodeURIComponent( query_url ) }`;

return getRequest( requestUrl, getParams )
.then( checkStatus )
.then( parseJsonResponse )
.then( messages => ( head( messages ) ) );
},

dismissJitm: ( id, feature_class ) => postRequest(
`${ apiRoot }jetpack/v4/jitm`,
postParams,
{
body: JSON.stringify( { id, feature_class } )
}
)
.then( checkStatus )
.then( parseJsonResponse )
};

function addCacheBuster( route ) {
Expand Down
7 changes: 7 additions & 0 deletions _inc/client/state/action-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,10 @@ export const JETPACK_SITE_VERIFY_GOOGLE_VERIFY_FETCH_SUCCESS = 'JETPACK_SITE_VER
export const JETPACK_SITE_VERIFY_GOOGLE_REQUEST = 'JETPACK_SITE_VERIFY_GOOGLE_REQUEST';
export const JETPACK_SITE_VERIFY_GOOGLE_REQUEST_SUCCESS = 'JETPACK_SITE_VERIFY_GOOGLE_REQUEST_SUCCESS';
export const JETPACK_SITE_VERIFY_GOOGLE_REQUEST_FAIL = 'JETPACK_SITE_VERIFY_GOOGLE_REQUEST_FAIL';

export const JITM_FETCH = 'JITM_FETCH';
export const JITM_FETCH_RECEIVE = 'JITM_FETCH_RECEIVE';
export const JITM_FETCH_FAIL = 'JITM_FETCH_FAIL';
export const JITM_DISMISS = 'JITM_DISMISS';
export const JITM_DISMISS_SUCCESS = 'JITM_DISMISS_SUCCESS';
export const JITM_DISMISS_FAIL = 'JITM_DISMISS_FAIL';
56 changes: 56 additions & 0 deletions _inc/client/state/jitm/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* Internal dependencies
*/
import {
JITM_FETCH,
JITM_FETCH_RECEIVE,
JITM_FETCH_FAIL,
JITM_DISMISS,
JITM_DISMISS_SUCCESS,
JITM_DISMISS_FAIL,
} from 'state/action-types';
import restApi from 'rest-api';

export const fetchJitm = ( message_path = '', query_url = 'page=jetpack' ) => {
return dispatch => {
dispatch( {
type: JITM_FETCH
} );
return restApi
.fetchJitm( message_path, query_url )
.then( message => {
dispatch( {
type: JITM_FETCH_RECEIVE,
message: message
} );
} )
.catch( error => {
dispatch( {
type: JITM_FETCH_FAIL,
error: error
} );
} );
};
};

export const getJitmDismissalResponse = ( id, feature_class ) => {
return dispatch => {
dispatch( {
type: JITM_DISMISS
} );
return restApi
.dismissJitm( id, feature_class )
.then( response => {
dispatch( {
type: JITM_DISMISS_SUCCESS,
response: response
} );
} )
.catch( error => {
dispatch( {
type: JITM_DISMISS_FAIL,
error: error
} );
} );
};
};
9 changes: 9 additions & 0 deletions _inc/client/state/jitm/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Internal dependencies
*/
import * as reducer from './reducer';
import * as actions from './actions';

const all = { ...reducer, ...actions };

export default all;
102 changes: 102 additions & 0 deletions _inc/client/state/jitm/reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* External dependencies
*/
import { combineReducers } from 'redux';
import get from 'lodash/get';
import assign from 'lodash/assign';

/**
* Internal dependencies
*/
import {
JITM_FETCH,
JITM_FETCH_RECEIVE,
JITM_FETCH_FAIL,
JITM_DISMISS,
JITM_DISMISS_SUCCESS,
JITM_DISMISS_FAIL
} from 'state/action-types';

export const data = ( state = {}, action ) => {
switch ( action.type ) {
case JITM_FETCH_RECEIVE:
return assign( {}, state, { message: action.message } );
case JITM_DISMISS_SUCCESS:
return assign( {}, state, { response: action.response } );
default:
return state;
}
};

export const initialRequestsState = {
isFetchingJitm: false,
isDismissingJitm: false,
};

export const requests = ( state = initialRequestsState, action ) => {
switch ( action.type ) {
case JITM_FETCH:
return assign( {}, state, {
isFetchingJitm: true
} );
case JITM_FETCH_RECEIVE:
case JITM_FETCH_FAIL:
return assign( {}, state, {
isFetchingJitm: false
} );
case JITM_DISMISS:
return assign( {}, state, {
isDismissingJitm: true
} );
case JITM_DISMISS_SUCCESS:
case JITM_DISMISS_FAIL:
return assign( {}, state, {
isDismissingJitm: false
} );
default:
return state;
}
};

export const reducer = combineReducers( {
data,
requests
} );

/**
* Returns true if currently requesting a JITM message. Otherwise false.
*
* @param {Object} state Global state tree
* @return {Boolean} Whether a JITM is being requested
*/
export function isFetchingJitm( state ) {
return !! state.jetpack.jitm.requests.isFetchingJitm;
}

/**
* Returns true if currently requesting the dismissal of a JITM message. Otherwise false.
*
* @param {Object} state Global state tree
* @return {Boolean} Whether a JITM is being dismissed.
*/
export function isDismissingJitm( state ) {
return !! state.jetpack.jitm.requests.isDismissingJitm;
}

/**
* Returns the current JITM message
* @param {Object} state Global state tree
* @return {Object} Features
*/
export function getJitm( state ) {
return get( state.jetpack.jitm, [ 'data', 'message' ], {} );
}

/**
* Dismiss the current JITM message
* @param {Object} state Global state tree
* @return {Object} Response
*/
export function getJitmDismissalResponse( state ) {
return get( state.jetpack.jitm, [ 'data', 'response' ], {} );
}
50 changes: 50 additions & 0 deletions _inc/client/state/jitm/test/reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { expect } from 'chai';

import {
data as dataReducer,
requests as requestsReducer,
initialRequestsState
} from '../reducer';

describe( 'data reducer', () => {
it( 'data state should default to empty object', () => {
const state = dataReducer( undefined, {} );
expect( state ).to.eql( {} );
} );
} );

describe( 'requests reducer', () => {
it( 'requests state should default to empty object', () => {
const state = requestsReducer( undefined, {} );
expect( state ).to.eql( initialRequestsState );
} );

describe( '#fetchJitm', () => {
it( 'should set isFetchingJitm to true when fetching JITMs', () => {
const stateIn = {};
const action = {
type: 'JITM_FETCH'
};
let stateOut = requestsReducer( stateIn, action );
expect( stateOut.isFetchingJitm ).to.be.true;
} );

it( 'should set isFetchingJitm to false when JITM fetch succeeds', () => {
const stateIn = {};
const action = {
type: 'JITM_FETCH_RECEIVE'
};
let stateOut = requestsReducer( stateIn, action );
expect( stateOut.isFetchingJitm ).to.be.false;
} );

it( 'should set isFetchingJitm to false when fetching JITMs fails', () => {
const stateIn = {};
const action = {
type: 'JITM_FETCH_FAIL'
};
let stateOut = requestsReducer( stateIn, action );
expect( stateOut.isFetchingJitm ).to.be.false;
} );
} );
} );
38 changes: 38 additions & 0 deletions _inc/client/state/jitm/test/selectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { expect } from 'chai';

import {
fetchJitm,
getJitm,
isFetchingJitm,
} from '../reducer';

let state = {
jetpack: {
jitm: {
data: {
message: 'Hi'
},
requests: {
isFetchingJitm: true
}
}
}
};

describe( 'status selectors', () => {
describe( '#getJitm', () => {
it( 'should return state.jetpack.jitm.data.message', () => {
const stateIn = state;
const output = getJitm( stateIn );
expect( output ).to.equal( state.jetpack.jitm.data.message );
} );
} );

describe( '#isFetchingJitm', () => {
it( 'should return state.jetpack.jitm.requests.isFetchingJim', () => {
const stateIn = state;
const output = isFetchingJitm( stateIn );
expect( output ).to.equal( state.jetpack.jitm.requests.isFetchingJitm );
} );
} );
} )
4 changes: 3 additions & 1 deletion _inc/client/state/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { reducer as search } from 'state/search/reducer';
import { reducer as devCard } from 'state/dev-version/reducer';
import { reducer as publicize } from 'state/publicize/reducer';
import { reducer as siteVerify } from 'state/site-verify/reducer';
import { reducer as jitm } from 'state/jitm/reducer';

const jetpackReducer = combineReducers( {
initialState,
Expand All @@ -39,7 +40,8 @@ const jetpackReducer = combineReducers( {
search,
devCard,
publicize,
siteVerify
siteVerify,
jitm,
} );

export default combineReducers( {
Expand Down