function model(options) { const { namespace, state = {}, mutations = {}, actions = {} } = options; let { setups = {} } = options; assert(namespace, `model namespace must be exsit`); assert(undefined === app._models[namespace], `model[namespace=${namespace}] must be union`); app._models[namespace] = namespace; // init reducer for (let rName in mutations) { if (!mutations.hasOwnProperty(rName)) continue; // 默认的 action 会对 mutations 里面的 key 进行赋值 !actions[rName] && (actions[rName] = payload => payload); mutations[prefix(namespace, rName)] = produceWrapp(mutations[rName]); delete mutations[rName]; } app._reducers[namespace] = handleActions(mutations, state); // add actions meta for (let actionName in actions) { const payloadCreator = actions[actionName]; // _composeDispatcher[namespace] 不可以在此取值,它只是容器,是动态添值的 const metaCreator = () => ({ namespace, app, takes: _takes, composeDispatcher: _composeDispatcher, }); actions[actionName] = [payloadCreator, metaCreator]; } // https://redux-actions.js.org/docs/api/createAction.html#createactionsactionmap app._actions[namespace] = createActions({ [namespace]: actions })[namespace]; if (typeof setups === 'function') { setups = { setup: setups }; } app._setups[namespace] = setups; }
/** * Any actions related to the applications-wide error handling and messaging. */ import _ from 'lodash'; import { createActions } from 'redux-actions'; /** * Export Actions for usage by Redux */ export default createActions({ ERRORS: { CLEAR_ERROR: _.noop, NEW_ERROR: (title, details) => ({ title, details }), CLEAR_ALL_ERROR_ICONS: _.noop, SET_ERROR_ICON: (id, title, message) => ({ id, title, message }), CLEAR_ERROR_ICON: id => ({ id }), }, });
import { createActions } from 'redux-actions'; export const { pageLoadRequest, pageLoadSuccess, pageLoadFailure } = createActions('PAGE_LOAD_REQUEST', 'PAGE_LOAD_SUCCESS', 'PAGE_LOAD_FAILURE'); const ACTION_HANDLERS = { ['PAGE_LOAD_REQUEST']: (state, action) => ({ ...state, pageLoading: true }), ['PAGE_LOAD_SUCCESS']: (state, action) => ({ ...state, pageLoading: false }), ['PAGE_LOAD_FAILURE']: (state, action) => ({ ...state, pageLoading: false }), } const initialState = { pageLoading:false } export default function Reducer(state = initialState, action) { const handler = ACTION_HANDLERS[action.type] return handler ? handler(state, action) : state }
clearUpdateTodo, openEditingPlannerItem, cancelEditingPlannerItem, setNaiAboveScreen, scrollToNewActivity, scrollToToday, } = createActions( 'INITIAL_OPTIONS', 'ADD_OPPORTUNITIES', 'START_LOADING_OPPORTUNITIES', 'START_DISMISSING_OPPORTUNITY', 'ALL_OPPORTUNITIES_LOADED', 'SAVING_PLANNER_ITEM', 'SAVED_PLANNER_ITEM', 'DISMISSED_OPPORTUNITY', 'DELETING_PLANNER_ITEM', 'DELETED_PLANNER_ITEM', 'UPDATE_TODO', 'CLEAR_UPDATE_TODO', 'OPEN_EDITING_PLANNER_ITEM', 'CANCEL_EDITING_PLANNER_ITEM', 'SET_NAI_ABOVE_SCREEN', 'SCROLL_TO_NEW_ACTIVITY', 'SCROLL_TO_TODAY', ); export * from './loading-actions'; function saveExistingPlannerItem (apiItem) { return axios({ method: 'put',
* @param {String} tokenV3 Topcoder v3 auth token. * @param {Number|String} submissionId Submission ID. * @return {Action} */ function deleteSubmissionDone(tokenV3, submissionId) { return getApiV3(tokenV3).delete(`/submissions/${submissionId}`) .then(() => submissionId); } /** * @static * @todo At this moment we don't need any special JS code to download * submissions: we get them from legacy Topcoder Studio API, which is * authenticated by cookies, and can be done with a simple <a> link in * the component. Soon we'll migrate to use the new TC API instead, and * then we'll decide, whether we need operate downloads in JS, or can we * just remove this action. * @return {Action} */ function downloadSubmission(tokens, type, submissionId) { _.noop(tokens, type, submissionId); } export default createActions({ SMP: { DELETE_SUBMISSION_DONE: deleteSubmissionDone, DELETE_SUBMISSION_INIT: deleteSubmissionInit, DOWNLOAD_SUBMISSION: downloadSubmission, }, });
/** * Actions for settings page UI. */ import _ from 'lodash'; import { createActions } from 'redux-actions'; export default createActions({ SETTINGS: { PROFILE: { TOGGLE_TAB: _.identity, }, TOOLS: { TOGGLE_TAB: _.identity, }, }, });
export default createActions({ CHALLENGE_LISTING: { SIDEBAR: { CHANGE_FILTER_NAME: changeFilterName, DELETE_SAVED_FILTER: deleteSavedFilter, DRAG_SAVED_FILTER_MOVE: dragSavedFilterMove, DRAG_SAVED_FILTER_START: dragSavedFilterStart, GET_SAVED_FILTERS: getSavedFilters, RESET_FILTER_NAME: resetFilterName, SAVE_FILTER_DONE: saveFilter, SAVE_FILTER_INIT: _.noop, /* Pass in the bucket type. */ SELECT_BUCKET: _.identity, /* Pass in the index of filter inside savedFilters array. */ SELECT_SAVED_FILTER: _.identity, /* Pass in true/false to enable/disable. */ SET_EDIT_SAVED_FILTERS_MODE: _.identity, UPDATE_ALL_SAVED_FILTERS: updateAllSavedFilters, UPDATE_SAVED_FILTER: updateSavedFilter, }, }, });
import { createActions } from 'redux-actions'; export const { push, pop, back } = createActions('push', 'pop', 'back');
*/ function getListInit(uuid) { return uuid; } /** * Payload creator for the action that fetches the list of communities visible * to the user. * @param {String} uuid Operation UUID. Should match with the one passed to * getListInit(). * @param {Object} auth Authorization data object. * @return {Promise} */ function getListDone(uuid, auth) { const groups = _.get(auth, 'profile.groups', []).map(g => g.id); return getCommunitiesService(auth.tokenV3) .getList(groups).then(list => ({ list, uuid })); } export default createActions({ TC_COMMUNITY: { GET_LIST_INIT: getListInit, GET_LIST_DONE: getListDone, HIDE_JOIN_BUTTON: _.noop, JOIN_INIT: _.noop, JOIN_DONE: joinDone, RESET_JOIN_BUTTON: _.noop, SHOW_JOIN_CONFIRM_MODAL: _.noop, }, });
import { createActions } from 'redux-actions'; export default createActions( { setInstalled: installed => ({ installed: installed || {}, installedLoaded: !!installed }) }, 'setHasAddon', 'setClientUuid', 'setInstalledAddons', 'enableExperiment', 'disableExperiment', 'requireRestart' );
function agreeTermInit(termId) { return _.toString(termId); } /** * @static * @desc Creates an action that agrees to a term. * @param {Number|String} termId id of term * @param {String} tokenV2 auth token * @return {Action} */ function agreeTermDone(termId, tokenV2) { const service = getService(tokenV2); return service.agreeTerm(termId).then(resp => ({ termId, success: resp.success })); } export default createActions({ TERMS: { GET_TERMS_INIT: getTermsInit, GET_TERMS_DONE: getTermsDone, GET_TERM_DETAILS_INIT: getTermDetailsInit, GET_TERM_DETAILS_DONE: getTermDetailsDone, GET_DOCU_SIGN_URL_INIT: getDocuSignUrlInit, GET_DOCU_SIGN_URL_DONE: getDocuSignUrlDone, AGREE_TERM_INIT: agreeTermInit, AGREE_TERM_DONE: agreeTermDone, CHECK_STATUS_INIT: checkStatusInit, CHECK_STATUS_DONE: checkStatusDone, }, });
import { createActions } from 'redux-actions' import Weather from '../lib/weather' function S4() { return (((1+Math.random())*0x10000)|0).toString(16).substring(1) } // a unique enough ID. Almost, but not quite a UUID function _newID() { return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4()).toLowerCase(); } const Actions = createActions({ }, 'INCREMENT', 'EDIT_BLOCK', 'DESTROY_BLOCK', 'ADD_BLOCK', 'TOGGLE_EDITING', 'TOGGLE_BLOCK_EDITOR', 'TOGGLE_SETTINGS_EDITOR', ) Actions.updateBlock = (id, attrs) => { return (dispatch, getState) => { const state = getState() const block = state.blocks[id] if (block) { dispatch({ type: 'UPDATE_BLOCK', payload: { ...block, ...attrs } }) } else {
* Payload creator for the action that actually loads all scheduled * announcements, bypassing the cache, as it is intended for use by editors. * @param {String} uuid * @return {Object} */ async function getScheduledDone(uuid) { const data = []; const index = _.keys(await getCurrentDashboardAnnouncementsIndex()); for (let i = 0; i !== index.length; i += 1) { /* eslint-disable no-await-in-loop */ data.push(await cdnService.getContentEntry(index[i])); /* eslint-enable no-await-in-loop */ } return { uuid, data }; } export default createActions({ CMS: { DASHBOARD: { ANNOUNCEMENTS: { GET_ACTIVE_INIT: getActiveInit, GET_ACTIVE_DONE: getActiveDone, GET_PREVIEW_INIT: getPreviewInit, GET_PREVIEW_DONE: getPreviewDone, GET_SCHEDULED_INIT: getScheduledInit, GET_SCHEDULED_DONE: getScheduledDone, }, }, }, });
/** 建立action action返回数据类似 { // action类型 type: navType, // action动作数据 payload: result, } */ export const { /** *禁止缓存 *@param boolean 是否禁止缓存 */ disCache, /** *禁止缓存 *@param boolean 是否打开录制 */ monitorStatus, /** *是否打开过滤器 *@param boolean 是否打开过滤器 */ monitorFilterStatus, /** * 刷新缓存,插入 meta标签只有 contentType是text/html时候管用 */ cacheFlush } = result = createActions(...Object.keys(navType)); export default result;
import { createActions } from 'redux-actions'; export default createActions({ updateExperiment: (addonID, data) => ({ addonID, data }), fetchExperiments: (experimentsUrl, countsUrl) => { let experiments = []; return fetch(experimentsUrl) .then(response => response.json()) .then(data => { experiments = data.results; return fetch(countsUrl); }) .then(response => response.json()) .then(counts => ({ lastFetched: Date.now(), experimentsLoaded: true, data: experiments.map(experiment => ({ ...experiment, installation_count: counts[experiment.addon_id] })) })); } });
/** * @static * @desc Creates an action that sets Topcoder v2 authentication token. * @param {String} tokenV2 Topcoder v2 authentication token. * @return {Action} */ function setTcTokenV2(tokenV2) { return tokenV2; } /** * @static * @desc Creates an action that decodes Topcoder v3 authentication token, * to get user object, and then writes both the token and the user object into * Redux store. * @param {String} tokenV3 Topcoder v3 authentication token. * @return {Action} */ function setTcTokenV3(tokenV3) { return tokenV3; } export default createActions({ AUTH: { LOAD_PROFILE: loadProfileDone, SET_TC_TOKEN_V2: setTcTokenV2, SET_TC_TOKEN_V3: setTcTokenV3, }, });
* @return {String} Topcoder auth token v3. */ function getUserProjectsInit(tokenV3) { return tokenV3; } /** * Payload creator for the actio that actually pulls from API the projects * related to user. * @param {String} tokenV3 Topcoder auth token v3. * @return {Object} Pull result object + some meta-information. */ async function getUserProjectsDone(tokenV3) { const projects = await getService(tokenV3).getUserProjects({ hasActiveBillingAccount: true, }); return { tokenV3, projects }; } export default createActions({ DIRECT: { DROP_ALL: dropAll, GET_PROJECT_DETAILS_INIT: getProjectDetailsInit, GET_PROJECT_DETAILS_DONE: getProjectDetailsDone, GET_PROJECT_PERMISSIONS_INIT: getProjectPermissionsInit, GET_PROJECT_PERMISSIONS_DONE: getProjectPermissionsDone, GET_USER_PROJECTS_INIT: getUserProjectsInit, GET_USER_PROJECTS_DONE: getUserProjectsDone, }, });
const types = [ 'LOAD_COURSES_START', 'LOAD_COURSES_SUCCESS', 'LOAD_COURSES_FAIL', 'LOAD_ASSOCIATIONS_START', 'LOAD_ASSOCIATIONS_SUCCESS', 'LOAD_ASSOCIATIONS_FAIL', 'LOAD_HISTORY_START', 'LOAD_HISTORY_SUCCESS', 'LOAD_HISTORY_FAIL', 'SAVE_ASSOCIATIONS_START', 'SAVE_ASSOCIATIONS_SUCCESS', 'SAVE_ASSOCIATIONS_FAIL', 'CHECK_MIGRATION_START', 'CHECK_MIGRATION_SUCCESS', 'CHECK_MIGRATION_FAIL', 'BEGIN_MIGRATION_START', 'BEGIN_MIGRATION_SUCCESS', 'BEGIN_MIGRATION_FAIL', 'ADD_COURSE_ASSOCIATIONS', 'UNDO_ADD_COURSE_ASSOCIATIONS', 'REMOVE_COURSE_ASSOCIATIONS', 'UNDO_REMOVE_COURSE_ASSOCIATIONS', 'CLEAR_ASSOCIATIONS', 'LOAD_UNSYNCED_CHANGES_START', 'LOAD_UNSYNCED_CHANGES_SUCCESS', 'LOAD_UNSYNCED_CHANGES_FAIL', 'ENABLE_SEND_NOTIFICATION', 'INCLUDE_CUSTOM_NOTIFICATION_MESSAGE', 'SET_NOTIFICATION_MESSAGE', 'LOAD_CHANGE_START', 'LOAD_CHANGE_SUCCESS', 'LOAD_CHANGE_FAIL', 'SELECT_CHANGE_LOG', 'NOTIFY_INFO', 'NOTIFY_ERROR', 'CLEAR_NOTIFICATION', 'INCLUDE_COURSE_SETTINGS' ] const actions = createActions(...types) actions.constants = { MIGRATION_POLL_TIME: 3000, } const { notifyInfo, notifyError } = actions actions.notifyInfo = payload => notifyInfo(Object.assign(payload, { type: 'info' })) actions.notifyError = payload => notifyError(Object.assign(payload, { type: 'error' })) actions.loadChange = params => (dispatch, getState) => { const state = getState() const change = state.changeLogs[params.changeId] if (change && LoadStates.isLoading(change.status)) return; dispatch(actions.loadChangeStart(params))
import {Map, Record, List} from 'immutable'; //Actions export const { addPlayerToGame, removePlayerFromGame, addPointToDrawing, endPathInDrawing, sendAddPoint, sendEndPath, sendChatMessage, addChatMessage, gameStart, correctGuess, outOfTime, intermissionOver, leaveGame} = createActions( { ADD_CHAT_MESSAGE: (name, message) => Map({name, message}), CORRECT_GUESS: (guesser, word) => ({guesser, word}) }, 'SEND_CHAT_MESSAGE', 'ADD_PLAYER_TO_GAME', 'REMOVE_PLAYER_FROM_GAME', 'ADD_POINT_TO_DRAWING', 'SEND_ADD_POINT', 'END_PATH_IN_DRAWING', 'SEND_END_PATH', 'GAME_START', 'OUT_OF_TIME', 'INTERMISSION_OVER', 'LEAVE_GAME' ); //Selectors export function getChatMessages(state){ return state.chatMessages; } //Default State export const GameRecord = Record({ id: undefined,
/** * Created by andrew on 12/11/16. */ import { createAction, createActions } from 'redux-actions'; import { timestamp } from '../utils/timestamp'; export const { wsEstablished, wsTerminated, wsLostConnection, wsNotConnecting, wsIncomingMessage, wsEvent, wsServerCommand } = createActions({ WS_ESTABLISHED: () => ({}), WS_TERMINATED: () => ({}), WS_LOST_CONNECTION: () => ({}), WS_NOT_CONNECTING: [(code, reason) => ({ code, reason }), timestamp ], WS_INCOMING_MESSAGE: [(message) => ({message}), (_, timestamp) => timestamp ? ({timestamp}) : timestamp], WS_EVENT: (data) => ({ data }), WS_SERVER_COMMAND: (data) => ({ data }) }); export const wsLostConnectionAsync = () => dispatch => { const timestamp = new Date() - 0; const reconnectionAttempts = 3; dispatch(wsLostConnection()); // TODO: Add reconnection logic };
'CHOOSE_DUPLICATE', // choose from a set of duplicates 'SKIP_DUPLICATE', // skip this set of duplicates 'ENQUEUE_NEW_FOR_DUPLICATE', // prepare to create a new user in lieu of one of the duplicates 'ENQUEUE_NEW_FOR_MISSING', // prepare to create a new user for one of the missing users 'ENQUEUE_USERS_TO_BE_ENROLLED', // prepare to enroll validated users 'RESET' // reset([array of state subsections to reset]) undefined or empty = reset everything ]; export const actionTypes = actionDefs.reduce((types, action) => { types[action] = action; // eslint-disable-line no-param-reassign return types; }, {}); export const actions = createActions(...actionDefs); actions.validateUsers = () => (dispatch, getState) => { dispatch(actions.validateUsersStart()); const state = getState(); const courseId = state.courseParams.courseId; let users = parseNameList(state.inputParams.nameList); if (state.inputParams.searchType === 'cc_path') { // normalize the input to be "User Name <email address>" // 1. include the email address w/in < ... > // 2. if the user includes a name and email, be sure the name is first users = users.map((u) => { let email = findEmailInEntry(u); let user = u.replace(email, ''); if (!/<.+>/.test(email)) { email = `<${email}>`;
import { createActions } from 'redux-actions'; const identity = x => x; export const loadingActions = createActions({ SHOW_LOADING: identity, HIDE_LOADING: identity }); export const namesActions = createActions({ ADD_NAME: identity, ADD_NAME_SUCCESS: identity, DELETE_NAME: identity, DELETE_NAME_SUCCESS: identity }); export const gridActions = createActions({ ADD_GRID_TYPE: identity, ADD_GRID_TYPE_SUCCESS: identity });
'SAVING_SETTINGS_FAIL', 'UPDATE_DISCUSSION_START', 'UPDATE_DISCUSSION_SUCCESS', 'UPDATE_DISCUSSION_FAIL', 'DUPLICATE_DISCUSSION_START', 'DUPLICATE_DISCUSSION_SUCCESS', 'DUPLICATE_DISCUSSION_FAIL', 'DELETE_DISCUSSION_START', 'DELETE_DISCUSSION_SUCCESS', 'DELETE_DISCUSSION_FAIL', 'DELETE_FOCUS_PENDING', 'DELETE_FOCUS_CLEANUP', 'CLEAN_DISCUSSION_FOCUS' ] const actions = Object.assign(createActions(...types), discussionActions.actionCreators) function copyAndUpdateDiscussion(discussion, updatedFields, focusOn) { const discussionCopy = Object.assign({}, discussion) Object.keys(updatedFields).forEach(key => { if (!Object.prototype.hasOwnProperty.call(discussion, key)) { throw new Error(`field ${key} does not exist in the discussion`) } discussionCopy[key] = updatedFields[key] }) if (focusOn) { discussionCopy.focusOn = focusOn } return discussionCopy }
import {createActions} from 'redux-actions'; export const { audiosAddMultiple } = createActions( 'AUDIOS_ADD_MULTIPLE' );
export default createActions({ PROFILE: { LOAD_PROFILE: loadProfile, GET_ACHIEVEMENTS_INIT: getAchievementsInit, GET_ACHIEVEMENTS_DONE: getAchievementsDone, GET_EXTERNAL_ACCOUNTS_INIT: getExternalAccountsInit, GET_EXTERNAL_ACCOUNTS_DONE: getExternalAccountsDone, GET_EXTERNAL_LINKS_INIT: getExternalLinksInit, GET_EXTERNAL_LINKS_DONE: getExternalLinksDone, GET_INFO_INIT: getInfoInit, GET_INFO_DONE: getInfoDone, GET_SKILLS_INIT: getSkillsInit, GET_SKILLS_DONE: getSkillsDone, GET_STATS_INIT: getStatsInit, GET_STATS_DONE: getStatsDone, GET_LINKED_ACCOUNTS_INIT: getLinkedAccountsInit, GET_LINKED_ACCOUNTS_DONE: getLinkedAccountsDone, GET_EMAIL_PREFERENCES_INIT: getEmailPreferencesInit, GET_EMAIL_PREFERENCES_DONE: getEmailPreferencesDone, GET_CREDENTIAL_INIT: getCredentialInit, GET_CREDENTIAL_DONE: getCredentialDone, UPLOAD_PHOTO_INIT: uploadPhotoInit, UPLOAD_PHOTO_DONE: uploadPhotoDone, DELETE_PHOTO_INIT: deletePhotoInit, DELETE_PHOTO_DONE: updateProfileDone, UPDATE_PROFILE_INIT: updateProfileInit, UPDATE_PROFILE_DONE: updateProfileDone, ADD_SKILL_INIT: addSkillInit, ADD_SKILL_DONE: addSkillDone, HIDE_SKILL_INIT: hideSkillInit, HIDE_SKILL_DONE: hideSkillDone, ADD_WEB_LINK_INIT: addWebLinkInit, ADD_WEB_LINK_DONE: addWebLinkDone, DELETE_WEB_LINK_INIT: deleteWebLinkInit, DELETE_WEB_LINK_DONE: deleteWebLinkDone, LINK_EXTERNAL_ACCOUNT_INIT: linkExternalAccountInit, LINK_EXTERNAL_ACCOUNT_DONE: linkExternalAccountDone, UNLINK_EXTERNAL_ACCOUNT_INIT: unlinkExternalAccountInit, UNLINK_EXTERNAL_ACCOUNT_DONE: unlinkExternalAccountDone, SAVE_EMAIL_PREFERENCES_INIT: saveEmailPreferencesInit, SAVE_EMAIL_PREFERENCES_DONE: saveEmailPreferencesDone, UPDATE_PASSWORD_INIT: updatePasswordInit, UPDATE_PASSWORD_DONE: updatePasswordDone, }, });
import selectn from 'selectn' import { stringify } from 'query-string' import { createAction, createActions } from 'redux-actions' import { checkStatus, parseJSON, headersAndBody } from'browser/redux/actions/actionHelpers' const forumsUrl = process.env.API_URL + 'forums/' const threadsUrl = process.env.API_URL + 'threads/' export const actions = createActions({ UNLOAD_FORUM: () => null, REMOVE_FORUM: id => id, TOGGLE_DIALOG: () => null, ADD_FORUM: forum => forum, RECIEVE_FORUM: forum => forum, RECIEVE_FORUMS: forums => forums, ADD_THREAD: thread => thread, RECIEVE_THREAD: thread => thread, UPDATE_FORUM: object => object, TOGGLE_FORUM_FETCHING: boolean => boolean, FETCHING_ERROR: reason => reason, RECIEVE_SEARCHED_VIDEOS: videos => videos, }) /** * create a forum * @param {object} payload data to pass * @param {function} callback callback function */ export const insertForum = (payload, callback) => (dispatch, getState) => { return fetch(forumsUrl, headersAndBody(payload)) .then(checkStatus)
/** * Actions related to the header filter panel. */ import _ from 'lodash'; import { createActions } from 'redux-actions'; export default createActions({ CHALLENGE_LISTING: { FILTER_PANEL: { /* Expands / collapses the filter panel. */ SET_EXPANDED: _.identity, /* Updates text in the search bar, without applying it to the active * challenge filter. The text will be set to the filter when Enter is * pressed. */ SET_SEARCH_TEXT: _.identity, /* Shows / hides the modal with track switches (for mobile view only). */ SHOW_TRACK_MODAL: _.identity, }, }, });
import { createActions } from 'redux-actions'; const actions = createActions('INITIAL_SCREEN_SIZE', 'SCREEN_RESIZE'); export const { initialScreenSize, screenResize } = actions;
/** * Actions for the Data Fetch example. */ /* global fetch */ import _ from 'lodash'; import { createActions } from 'redux-actions'; function fetchDataDone() { /* NOTE: In the real life in most cases you don't want to use fetch() directly * in an action. You want to create a service for your calls and use it here. * However, in this example, to keep it a bit more compact, we use fetch() * directly here. */ return fetch('http://api.topcoder-dev.com/v2/challenges/active?type=develop') .then(res => res.json()).then(res => res.data); } export default createActions({ EXAMPLES: { DATA_FETCH: { FETCH_DATA_INIT: _.noop, FETCH_DATA_DONE: fetchDataDone, }, }, });
/** * Actions related to the UI state of member payments listing page. */ import { createActions } from 'redux-actions'; /** * Payload creator for the action that selects the specified project. * @param {Number} projectId * @return {String} Action payload. */ function selectProject(projectId) { return projectId; } export default createActions({ PAGE: { SANDBOX: { PAYMENTS: { LISTING: { SELECT_PROJECT: selectProject, }, }, }, }, });