Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"checkJs": true,
"types": [ "jest" ],
"types": [ "./src/index.d.ts", "jest" ],
"baseUrl": "./src"
},
"include": [ "./src/**/*.js", "./src/**/*.jsx" ],
Expand Down
11 changes: 11 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { CurriedSelectorsOf } from '@wordpress/data/build-types/types'
import { NoticeStore, NOTIFY_NAMESPACE } from './scripts/store'

declare global {
interface Window { wp: { notify: any }; wp_notify_data?: { settingsPage: string } }
}

declare module '@wordpress/data' {
function dispatch( key: NOTIFY_NAMESPACE ): typeof import( './scripts/store/actions' );
function select( key: NOTIFY_NAMESPACE ): CurriedSelectorsOf< NoticeStore >;
}
54 changes: 48 additions & 6 deletions src/scripts/store/actions.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,83 @@
/* eslint-disable jsdoc/require-returns-type */

/**
* @typedef {import('./index').Notice} Notice
*/

/**
* Action creator to hydrate a notice from the store.
*
* @param {Notice[]} payload The notices to hydrate.
* @return A redux action.
*/
export const hydrate = ( payload ) => {
return {
type: 'HYDRATE',
type: /** @type {'HYDRATE'} */ ( 'HYDRATE' ),

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is weird but required for it to be type 'HYDRATE' not string. Otherwise the type union in action types doesn't work right in the reducer.

payload,
};
};

/**
* Action creator to clear a notification context from the store.
*
* @param {string} context The slug of the context to clear.
* @return A redux action.
*/
export const clear = ( context ) => {
return {
type: 'CLEAR',
type: /** @type {'CLEAR'} */ ( 'CLEAR' ),
context,
};
};

/**
* Action creator to add a notice to the store.
*
* @param {Notice} payload The notice to add.
* @return A redux action.
*/
export const addNotice = ( payload ) => {
return {
type: 'ADD',
type: /** @type {'ADD'} */ ( 'ADD' ),
payload,
};
};

/**
* Action creator to remove a notice from the store.
*
* @param {number} id The id of the notice to remove.
* @return A redux action.
*/
export const removeNotice = ( id ) => {
return {
type: 'DELETE',
type: /** @type {'DELETE'} */ ( 'DELETE' ),
id,
};
};

/**
* Action creator to update a notice in the store.
*
* @param {Notice} payload
* @return A redux action.
*/
export const updateNotice = ( payload ) => {
return {
type: 'UPDATE',
type: /** @type {'UPDATE'} */ ( 'UPDATE' ),
payload,
};
};

/**
* Action creator to fetch notices.
*
* @param {string} path The REST API route from which to fetch notices.
* @return A redux action.
*/
export const fetchAPI = ( path = '' ) => {
return {
type: 'FETCH',
type: /** @type {'FETCH'} */ ( 'FETCH' ),
path,
};
};
5 changes: 3 additions & 2 deletions src/scripts/store/constants.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* global wp_notify_data */
/**
* @member {string} NOTIFY_NAMESPACE WP-Notify namespace
*/
Expand All @@ -24,4 +23,6 @@ export const contexts = [ defaultContext, 'dashboard' ];
*/
export const settingsPageUrl =
// eslint-disable-next-line camelcase
typeof wp_notify_data !== 'undefined' ? wp_notify_data?.settingsPage : '';
typeof window.wp_notify_data !== 'undefined'
? window.wp_notify_data?.settingsPage
: '';
7 changes: 5 additions & 2 deletions src/scripts/store/controls.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import apiFetch from '@wordpress/api-fetch';
import { API_PATH } from './constants';

/**
* @typedef {import('./index').Notice} Notice
*/
/**
* Fetches the wp-notify rest api endpoint for the specified endpoint
*
* @param {string} action - the action to execute
* @return {Promise} - the Promise with the results
* @param {{path: string}} action The action to execute
* @return {Promise<Notice>} The Promise with the results
*/
export const FETCH = ( action ) => {
return apiFetch( {
Expand Down
48 changes: 40 additions & 8 deletions src/scripts/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@ import * as controls from './controls';
import * as resolvers from './resolvers';

/**
<<<<<<< Updated upstream
=======
*
* @typedef {import('@wordpress/data/build-types/types').ReduxStoreConfig<State, typeof actions, typeof selectors>} StoreConfig
* @typedef {import('@wordpress/data/build-types/types').StoreDescriptor<StoreConfig>} NoticeStore
*/

/**
* @template {Record<string, unknown>} T
* @template {keyof T} K
* @typedef {T[K]} ValuesOf
*/

/**
* @typedef {ReturnType<ValuesOf<typeof actions, keyof actions>>} Action
*/

/**
>>>>>>> Stashed changes

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ARGH... JUST A SEC THESE SHOULDN'T BE HERE

*
* @typedef {Object} DashiconsIcon The Dashicons icon type.
* @property {string} dashicons The Dashicons slug of the icon.
*/
Expand All @@ -33,7 +53,12 @@ import * as resolvers from './resolvers';
*/

/**
<<<<<<< Updated upstream
*
* @typedef {Object} Notification The notification type.
=======
* @typedef {Object} Notice The notification type.
>>>>>>> Stashed changes
* @property {NoticeAction=} action The optional action associated to the notification.
* @property {string=} context The rendering context of the notification.
* @property {number} date The datetime from which the notification was emitted.
Expand All @@ -47,21 +72,28 @@ import * as resolvers from './resolvers';
*/

/**
<<<<<<< Updated upstream
*
* @typedef {Record<string, Notification[]>} State The notifications redux store type.
=======
* @typedef {Record<string, Notice[]>} State The notifications redux store type.
>>>>>>> Stashed changes
*/

/**
* Creating a store for the redux state.
*
* @return {store} A Redux store that lets you read the state, dispatch actions and subscribe to changes.
* A Redux store that lets you read the state, dispatch actions and subscribe to changes.
*/
const store = createReduxStore( NOTIFY_NAMESPACE, {
reducer,
actions,
selectors,
controls,
resolvers,
} );
const store = /** @type {NoticeStore} */ (
createReduxStore( NOTIFY_NAMESPACE, {
reducer,
actions,
selectors,
controls,
resolvers,
} )
);

register( store );

Expand Down
12 changes: 7 additions & 5 deletions src/scripts/store/reducer.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { findContext } from './utils';

/**
* @typedef {import('redux').Reducer<State, Action>} NoticeReducer
* @typedef {import('./index').State} State
* @typedef {import('./index').Action} Action
*/

/**
* Reducer returning the next notices state. The notices state is an object
* where each key is a context, its value an array of notice objects.
*
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
*
* @return {Object} Updated state.
* @type {NoticeReducer}
*/
const reducer = ( state = {}, action ) => {
switch ( action.type ) {
Expand All @@ -21,7 +24,6 @@ const reducer = ( state = {}, action ) => {
};
} );
return updated;

case 'ADD':
return {
...state,
Expand Down
23 changes: 15 additions & 8 deletions src/scripts/store/selectors.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import { __ } from '@wordpress/i18n';
import { findContext } from './utils';

/**
* @typedef {import('./index').Notice} Notice
* @typedef {import('./index').State} State
*/

/**
* Fetch the rest api in order to get new notifications
*
* @param {Object} state the current state
* @return {Object} the new notifications
* @param {State} state the current state
* @return {State} the new notifications
*/
export const fetchUpdates = ( state ) => state || {};

/**
* Get the notices for the given context
*
* @param {Object} state the current state
* @param {string} context the name of the list of notifications you want to retreive
* @param {State} state the current state
* @param {string} context the name of the list of notifications you want to retrieve
*
* @return {Object[]} the list of notices of the context
* @return {Notice[]|Record<string, Notice[]>} the list of notices of the context
*/
export const getNotices = ( state, context ) => {
return context ? state[ context ] : state;
Expand All @@ -25,8 +30,10 @@ export const getNotices = ( state, context ) => {
* Adds a context to the current state.
* commonly it's fired when the NotifyArea is registered
*
* @param {Object} state the current state
* @param {State} state the current state
* @param {string} context the context to add
*
* @return {State} the notice store state
*/
export const registerContext = ( state, context ) => {
if ( ! state[ context ] ) {
Expand All @@ -38,11 +45,11 @@ export const registerContext = ( state, context ) => {
/**
* It searches the Redux store for a notification by ID or by a search term
*
* @param {Object} state - the current state
* @param {State} state - the current state
* @param {string|number} searchTerm - The term you want to search for.
* @param {?Object|Array} [args] - search args
*
* @return {Object} the search result
* @return {Notice|Notice[]|string} the search result
*/
export const findNotice = ( state, searchTerm, args = { term: 'source' } ) => {
// return the notification by id
Expand Down
5 changes: 4 additions & 1 deletion src/scripts/store/utils.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
/**
* @typedef {import('./index').State} State
*/
/**
* Find the context for the given notification key.
*
* @param {Object} notifications - The notifications object to search in
* @param {State} notifications - The notifications object to search in
* @param {number} id - The notification id to search
*/
export function findContext( notifications, id ) {
Expand Down
Loading