use new notification state
This commit is contained in:
parent
6139cede26
commit
b295a7db57
12 changed files with 1041 additions and 772 deletions
1368
dist/bundle.js
vendored
1368
dist/bundle.js
vendored
File diff suppressed because it is too large
Load diff
|
@ -28,7 +28,8 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"proxy-polyfill": "0.1.6",
|
"proxy-polyfill": "0.1.6",
|
||||||
"reselect": "^3.0.0"
|
"reselect": "^3.0.0",
|
||||||
|
"uuid": "^3.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-core": "^6.26.0",
|
"babel-core": "^6.26.0",
|
||||||
|
|
|
@ -210,5 +210,10 @@ export const REMOVE_PENDING_PUBLISH = 'REMOVE_PENDING_PUBLISH';
|
||||||
export const DO_PREPARE_EDIT = 'DO_PREPARE_EDIT';
|
export const DO_PREPARE_EDIT = 'DO_PREPARE_EDIT';
|
||||||
|
|
||||||
// Notifications
|
// Notifications
|
||||||
export const CREATE_NOTIFICATION = 'CREATE_NOTIFICATION';
|
export const CREATE_EVENT = 'CREATE_EVENT';
|
||||||
export const DISMISS_NOTIFICATION = 'DISMISS_NOTIFICATION';
|
export const EDIT_EVENT = 'EDIT_EVENT';
|
||||||
|
export const DELETE_EVENT = 'DELETE_EVENT';
|
||||||
|
export const CREATE_TOAST = 'CREATE_TOAST';
|
||||||
|
export const DISMISS_TOAST = 'DISMISS_TOAST';
|
||||||
|
export const CREATE_ERROR = 'CREATE_ERROR';
|
||||||
|
export const DISMISS_ERROR = 'DISMISS_ERROR';
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
export const CONFIRM_FILE_REMOVE = 'confirm_file_remove';
|
|
||||||
export const CONFIRM_EXTERNAL_LINK = 'confirm_external_link';
|
|
||||||
export const INCOMPATIBLE_DAEMON = 'incompatible_daemon';
|
|
||||||
export const FILE_TIMEOUT = 'file_timeout';
|
|
||||||
export const DOWNLOADING = 'downloading';
|
|
||||||
export const AUTO_UPDATE_DOWNLOADED = 'auto_update_downloaded';
|
|
||||||
export const AUTO_UPDATE_CONFIRM = 'auto_update_confirm';
|
|
||||||
export const ERROR = 'error';
|
|
||||||
export const INSUFFICIENT_CREDITS = 'insufficient_credits';
|
|
||||||
export const UPGRADE = 'upgrade';
|
|
||||||
export const WELCOME = 'welcome';
|
|
||||||
export const EMAIL_COLLECTION = 'email_collection';
|
|
||||||
export const PHONE_COLLECTION = 'phone_collection';
|
|
||||||
export const FIRST_REWARD = 'first_reward';
|
|
||||||
export const AUTHENTICATION_FAILURE = 'auth_failure';
|
|
||||||
export const TRANSACTION_FAILED = 'transaction_failed';
|
|
||||||
export const REWARD_APPROVAL_REQUIRED = 'reward_approval_required';
|
|
||||||
export const REWARD_GENERATED_CODE = 'reward_generated_code';
|
|
||||||
export const AFFIRM_PURCHASE = 'affirm_purchase';
|
|
||||||
export const CONFIRM_CLAIM_REVOKE = 'confirm_claim_revoke';
|
|
||||||
export const FIRST_SUBSCRIPTION = 'firstSubscription';
|
|
||||||
export const SEND_TIP = 'send_tip';
|
|
||||||
export const SOCIAL_SHARE = 'social_share';
|
|
||||||
export const PUBLISH = 'publish';
|
|
||||||
export const SEARCH = 'search';
|
|
||||||
export const CONFIRM_TRANSACTION = 'confirm_transaction';
|
|
||||||
export const CONFIRM_THUMBNAIL_UPLOAD = 'confirm_thumbnail_upload';
|
|
||||||
export const WALLET_ENCRYPT = 'wallet_encrypt';
|
|
||||||
export const WALLET_DECRYPT = 'wallet_decrypt';
|
|
||||||
export const WALLET_UNLOCK = 'wallet_unlock';
|
|
22
src/index.js
22
src/index.js
|
@ -1,5 +1,4 @@
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import * as MODALS from 'constants/modal_types';
|
|
||||||
import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses';
|
import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses';
|
||||||
import * as SEARCH_TYPES from 'constants/search';
|
import * as SEARCH_TYPES from 'constants/search';
|
||||||
import * as SETTINGS from 'constants/settings';
|
import * as SETTINGS from 'constants/settings';
|
||||||
|
@ -12,19 +11,10 @@ import Lbryapi from 'lbryapi';
|
||||||
import { selectState as selectSearchState } from 'redux/selectors/search';
|
import { selectState as selectSearchState } from 'redux/selectors/search';
|
||||||
|
|
||||||
// types
|
// types
|
||||||
export { Notification } from 'types/Notification';
|
export { Toast } from 'types/Notification';
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
export {
|
export { ACTIONS, THUMBNAIL_STATUSES, SEARCH_TYPES, SETTINGS, TRANSACTIONS, SORT_OPTIONS, PAGES };
|
||||||
ACTIONS,
|
|
||||||
MODALS,
|
|
||||||
THUMBNAIL_STATUSES,
|
|
||||||
SEARCH_TYPES,
|
|
||||||
SETTINGS,
|
|
||||||
TRANSACTIONS,
|
|
||||||
SORT_OPTIONS,
|
|
||||||
PAGES,
|
|
||||||
};
|
|
||||||
|
|
||||||
// common
|
// common
|
||||||
export { Lbry, Lbryapi };
|
export { Lbry, Lbryapi };
|
||||||
|
@ -41,7 +31,7 @@ export {
|
||||||
} from 'lbryURI';
|
} from 'lbryURI';
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
export { doNotify, doHideNotification } from 'redux/actions/notifications';
|
export { doToast, doDismissToast, doError, doDismissError } from 'redux/actions/notifications';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
doFetchClaimsByChannel,
|
doFetchClaimsByChannel,
|
||||||
|
@ -108,11 +98,7 @@ export { blacklistReducer } from 'redux/reducers/blacklist';
|
||||||
// selectors
|
// selectors
|
||||||
export { selectBlackListedOutpoints } from 'redux/selectors/blacklist';
|
export { selectBlackListedOutpoints } from 'redux/selectors/blacklist';
|
||||||
|
|
||||||
export {
|
export { selectToast, selectError } from 'redux/selectors/notifications';
|
||||||
selectNotification,
|
|
||||||
selectNotificationProps,
|
|
||||||
selectSnack,
|
|
||||||
} from 'redux/selectors/notifications';
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
makeSelectClaimForUri,
|
makeSelectClaimForUri,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as ACTIONS from 'constants/action_types';
|
||||||
import Lbry from 'lbry';
|
import Lbry from 'lbry';
|
||||||
import Lbryapi from 'lbryapi';
|
import Lbryapi from 'lbryapi';
|
||||||
import { normalizeURI } from 'lbryURI';
|
import { normalizeURI } from 'lbryURI';
|
||||||
import { doNotify } from 'redux/actions/notifications';
|
import { doToast } from 'redux/actions/notifications';
|
||||||
import { selectMyClaimsRaw, selectResolvingUris } from 'redux/selectors/claims';
|
import { selectMyClaimsRaw, selectResolvingUris } from 'redux/selectors/claims';
|
||||||
import { batchActions } from 'util/batchActions';
|
import { batchActions } from 'util/batchActions';
|
||||||
import { doFetchTransactions } from 'redux/actions/wallet';
|
import { doFetchTransactions } from 'redux/actions/wallet';
|
||||||
|
@ -86,11 +86,9 @@ export function doAbandonClaim(txid, nout) {
|
||||||
|
|
||||||
const errorCallback = () => {
|
const errorCallback = () => {
|
||||||
dispatch(
|
dispatch(
|
||||||
doNotify({
|
doToast({
|
||||||
title: 'Transaction failed',
|
message: 'Transaction failed',
|
||||||
message: 'Error abandoning claim',
|
isError: true,
|
||||||
type: 'error',
|
|
||||||
displayType: ['snackbar', 'toast'],
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -104,10 +102,8 @@ export function doAbandonClaim(txid, nout) {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
dispatch(
|
dispatch(
|
||||||
doNotify({
|
doToast({
|
||||||
title: 'Transaction successful',
|
|
||||||
message: 'Successfully abandoned your claim',
|
message: 'Successfully abandoned your claim',
|
||||||
displayType: ['snackbar', 'toast'],
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -117,11 +113,9 @@ export function doAbandonClaim(txid, nout) {
|
||||||
dispatch(doFetchTransactions());
|
dispatch(doFetchTransactions());
|
||||||
} else {
|
} else {
|
||||||
dispatch(
|
dispatch(
|
||||||
doNotify({
|
doToast({
|
||||||
title: 'Transaction failed',
|
|
||||||
message: 'Error abandoning claim',
|
message: 'Error abandoning claim',
|
||||||
type: 'error',
|
isError: true,
|
||||||
displayType: ['snackbar', 'toast'],
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,39 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
import type { ToastParams } from 'types/Notification';
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import type { Notification, NotificationProps } from 'types/Notification';
|
import uuid from 'uuid/v4';
|
||||||
|
|
||||||
|
export function doToast(params: ToastParams) {
|
||||||
|
if (!params) {
|
||||||
|
throw Error("'params' object is required to create a toast notification");
|
||||||
|
}
|
||||||
|
|
||||||
export function doNotify(notification: Notification, notificationProps: NotificationProps) {
|
|
||||||
return {
|
return {
|
||||||
type: ACTIONS.CREATE_NOTIFICATION,
|
type: ACTIONS.CREATE_TOAST,
|
||||||
data: {
|
data: {
|
||||||
notification,
|
id: uuid(),
|
||||||
// using this syntax to create an object if notificationProps is undefined
|
params,
|
||||||
notificationProps: { ...notificationProps },
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doHideNotification() {
|
export function doDismissToast() {
|
||||||
return {
|
return {
|
||||||
type: ACTIONS.DISMISS_NOTIFICATION,
|
type: ACTIONS.DISMISS_TOAST,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doError(error: string | {}) {
|
||||||
|
return {
|
||||||
|
type: ACTIONS.CREATE_ERROR,
|
||||||
|
data: {
|
||||||
|
error,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDismissError() {
|
||||||
|
return {
|
||||||
|
type: ACTIONS.DISMISS_ERROR,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import Lbry from 'lbry';
|
import Lbry from 'lbry';
|
||||||
import { doNotify } from 'redux/actions/notifications';
|
import { doToast } from 'redux/actions/notifications';
|
||||||
import { selectBalance } from 'redux/selectors/wallet';
|
import { selectBalance } from 'redux/selectors/wallet';
|
||||||
import { creditsToString } from 'util/formatCredits';
|
import { creditsToString } from 'util/formatCredits';
|
||||||
|
|
||||||
|
@ -96,11 +96,9 @@ export function doSendDraftTransaction(address, amount) {
|
||||||
|
|
||||||
if (balance - amount <= 0) {
|
if (balance - amount <= 0) {
|
||||||
dispatch(
|
dispatch(
|
||||||
doNotify({
|
doToast({
|
||||||
title: 'Insufficient credits',
|
title: 'Insufficient credits',
|
||||||
message: 'Insufficient credits',
|
message: 'Insufficient credits',
|
||||||
type: 'error',
|
|
||||||
displayType: ['modal', 'toast'],
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
@ -116,11 +114,8 @@ export function doSendDraftTransaction(address, amount) {
|
||||||
type: ACTIONS.SEND_TRANSACTION_COMPLETED,
|
type: ACTIONS.SEND_TRANSACTION_COMPLETED,
|
||||||
});
|
});
|
||||||
dispatch(
|
dispatch(
|
||||||
doNotify({
|
doToast({
|
||||||
title: 'Credits sent',
|
|
||||||
message: `You sent ${amount} LBC`,
|
message: `You sent ${amount} LBC`,
|
||||||
type: 'error',
|
|
||||||
displayType: ['snackbar', 'toast'],
|
|
||||||
linkText: 'History',
|
linkText: 'History',
|
||||||
linkTarget: '/wallet',
|
linkTarget: '/wallet',
|
||||||
})
|
})
|
||||||
|
@ -131,11 +126,9 @@ export function doSendDraftTransaction(address, amount) {
|
||||||
data: { error: response },
|
data: { error: response },
|
||||||
});
|
});
|
||||||
dispatch(
|
dispatch(
|
||||||
doNotify({
|
doToast({
|
||||||
title: 'Transaction failed',
|
|
||||||
message: 'Transaction failed',
|
message: 'Transaction failed',
|
||||||
type: 'error',
|
isError: true,
|
||||||
displayType: ['snackbar', 'toast'],
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -147,11 +140,9 @@ export function doSendDraftTransaction(address, amount) {
|
||||||
data: { error: error.message },
|
data: { error: error.message },
|
||||||
});
|
});
|
||||||
dispatch(
|
dispatch(
|
||||||
doNotify({
|
doToast({
|
||||||
title: 'Transaction failed',
|
|
||||||
message: 'Transaction failed',
|
message: 'Transaction failed',
|
||||||
type: 'error',
|
isError: true,
|
||||||
displayType: ['snackbar', 'toast'],
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -184,11 +175,9 @@ export function doSendTip(amount, claimId, uri, successCallback, errorCallback)
|
||||||
|
|
||||||
if (balance - amount <= 0) {
|
if (balance - amount <= 0) {
|
||||||
dispatch(
|
dispatch(
|
||||||
doNotify({
|
doToast({
|
||||||
title: 'Insufficient credits',
|
|
||||||
message: 'Insufficient credits',
|
message: 'Insufficient credits',
|
||||||
type: 'error',
|
isError: true,
|
||||||
displayType: ['modal', 'toast'],
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
@ -196,11 +185,10 @@ export function doSendTip(amount, claimId, uri, successCallback, errorCallback)
|
||||||
|
|
||||||
const success = () => {
|
const success = () => {
|
||||||
dispatch(
|
dispatch(
|
||||||
doNotify({
|
doToast({
|
||||||
message: __(`You sent ${amount} LBC as a tip, Mahalo!`),
|
message: __(`You sent ${amount} LBC as a tip, Mahalo!`),
|
||||||
linkText: __('History'),
|
linkText: __('History'),
|
||||||
linkTarget: __('/wallet'),
|
linkTarget: __('/wallet'),
|
||||||
displayType: ['snackbar'],
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -215,9 +203,9 @@ export function doSendTip(amount, claimId, uri, successCallback, errorCallback)
|
||||||
|
|
||||||
const error = (err) => {
|
const error = (err) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
doNotify({
|
doToast({
|
||||||
message: __(`There was an error sending support funds.`),
|
message: __(`There was an error sending support funds.`),
|
||||||
displayType: ['snackbar'],
|
isError: true,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,55 +1,99 @@
|
||||||
|
// @flow
|
||||||
|
import type {
|
||||||
|
NotificationState,
|
||||||
|
DoToast,
|
||||||
|
DoEvent,
|
||||||
|
DoEditEvent,
|
||||||
|
DoDeleteEvent,
|
||||||
|
} from 'types/Notification';
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import * as MODALS from 'constants/modal_types';
|
import { handleActions } from 'util/redux-utils';
|
||||||
|
|
||||||
const reducers = {};
|
const defaultState: NotificationState = {
|
||||||
|
events: [],
|
||||||
const defaultState = {
|
toasts: [],
|
||||||
// First-in, first-out
|
errors: [],
|
||||||
queue: [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
reducers[ACTIONS.CREATE_NOTIFICATION] = (state, action) => {
|
const notificationsReducer = handleActions(
|
||||||
const { notification, notificationProps } = action.data;
|
{
|
||||||
const { title, message, type, error, displayType, id } = notification;
|
// Toasts
|
||||||
|
[ACTIONS.CREATE_TOAST]: (state: NotificationState, action: DoToast) => {
|
||||||
|
const toast = action.data;
|
||||||
|
const newToasts = state.toasts.slice();
|
||||||
|
newToasts.push(toast);
|
||||||
|
|
||||||
const queue = Object.assign([], state.queue);
|
return {
|
||||||
queue.push({
|
...state,
|
||||||
notification: {
|
toasts: newToasts,
|
||||||
id,
|
};
|
||||||
title,
|
|
||||||
message,
|
|
||||||
type,
|
|
||||||
error,
|
|
||||||
displayType,
|
|
||||||
},
|
},
|
||||||
notificationProps,
|
[ACTIONS.DISMISS_TOAST]: (state: NotificationState) => {
|
||||||
});
|
const newToasts = state.toasts.slice();
|
||||||
|
newToasts.shift();
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
return {
|
||||||
queue,
|
...state,
|
||||||
});
|
toasts: newToasts,
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
reducers[ACTIONS.DISMISS_NOTIFICATION] = state => {
|
// Events
|
||||||
const queue = Object.assign([], state.queue);
|
[ACTIONS.CREATE_EVENT]: (state: NotificationState, action: DoEvent) => {
|
||||||
queue.shift();
|
const event = action.data;
|
||||||
|
const newEvents = state.events.slice();
|
||||||
|
newEvents.push(event);
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
return {
|
||||||
queue,
|
...state,
|
||||||
});
|
events: newEvents,
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
// Used to mark notifications as read/dismissed
|
||||||
|
[ACTIONS.EDIT_EVENT]: (state: NotificationState, action: DoEditEvent) => {
|
||||||
|
const { event } = action.data;
|
||||||
|
let events = state.events.slice();
|
||||||
|
|
||||||
reducers[ACTIONS.HISTORY_NAVIGATE] = state => {
|
events = events.map((pastEvent) => (pastEvent.id === event.id ? event : pastEvent));
|
||||||
const queue = Object.assign([], state.queue);
|
|
||||||
if (queue[0] && queue[0].notification.id === MODALS.SEARCH) {
|
|
||||||
queue.shift();
|
|
||||||
return Object.assign({}, state, { queue });
|
|
||||||
}
|
|
||||||
return state;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function notificationsReducer(state = defaultState, action) {
|
return {
|
||||||
const handler = reducers[action.type];
|
...state,
|
||||||
if (handler) return handler(state, action);
|
events,
|
||||||
return state;
|
};
|
||||||
}
|
},
|
||||||
|
[ACTIONS.DELETE_EVENT]: (state: NotificationState, action: DoDeleteEvent) => {
|
||||||
|
const { id } = action.data;
|
||||||
|
let newEvents = state.events.slice();
|
||||||
|
newEvents = newEvents.filter((notification) => notification.id !== id);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
events: newEvents,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
// Errors
|
||||||
|
[ACTIONS.CREATE_ERROR]: (state: NotificationState, action: DoToast) => {
|
||||||
|
const error = action.data;
|
||||||
|
const newErrors = state.errors.slice();
|
||||||
|
newErrors.push(error);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
errors: newErrors,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[ACTIONS.DISMISS_ERROR]: (state: NotificationState) => {
|
||||||
|
const newErrors = state.errors.slice();
|
||||||
|
newErrors.shift();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
errors: newErrors,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultState
|
||||||
|
);
|
||||||
|
|
||||||
|
export { notificationsReducer };
|
||||||
|
|
|
@ -1,30 +1,26 @@
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
export const selectState = state => state.notifications || {};
|
export const selectState = (state) => state.notifications || {};
|
||||||
|
|
||||||
export const selectNotificationData = createSelector(
|
export const selectToast = createSelector(selectState, (state) => {
|
||||||
selectState,
|
if (state.toasts.length) {
|
||||||
state => (state.queue.length > 0 ? state.queue[0] : {})
|
const { id, params } = state.toasts[0];
|
||||||
);
|
return {
|
||||||
|
id,
|
||||||
export const selectNotification = createSelector(
|
...params,
|
||||||
selectNotificationData,
|
};
|
||||||
notificationData => notificationData.notification
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectNotificationProps = createSelector(
|
|
||||||
selectNotificationData,
|
|
||||||
notificationData => notificationData.notificationProps
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectSnack = createSelector(
|
|
||||||
// No props for snackbar
|
|
||||||
selectNotification,
|
|
||||||
notification => {
|
|
||||||
if (notification && notification.displayType) {
|
|
||||||
return notification.displayType.indexOf('snackbar') > -1 ? notification : undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const selectError = createSelector(selectState, (state) => {
|
||||||
|
if (state.errors.length) {
|
||||||
|
const { error } = state.errors[0];
|
||||||
|
return {
|
||||||
|
error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
|
@ -1,19 +1,97 @@
|
||||||
// @flow
|
// @flow
|
||||||
export type Notification = {
|
import * as ACTIONS from 'constants/action_types';
|
||||||
id: ?string,
|
|
||||||
title: ?string,
|
/*
|
||||||
|
Toasts:
|
||||||
|
- First-in, first-out queue
|
||||||
|
- Simple messages that are shown in response to user interactions
|
||||||
|
- Never saved
|
||||||
|
- If they are the result of errors, use the isError flag when creating
|
||||||
|
- For errors that should interrupt user behavior, use Error
|
||||||
|
*/
|
||||||
|
export type ToastParams = {
|
||||||
message: string,
|
message: string,
|
||||||
type: string,
|
title?: string,
|
||||||
error: ?string,
|
linkText?: string,
|
||||||
displayType: mixed,
|
linkTarget?: string,
|
||||||
|
isError?: boolean,
|
||||||
// additional properties for SnackBar
|
|
||||||
linkText: ?string,
|
|
||||||
linkTarget: ?string,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Used for retreiving data from redux store
|
export type Toast = {
|
||||||
export type NotificationProps = {
|
id: string,
|
||||||
uri: ?string,
|
params: ToastParams,
|
||||||
path: ?string,
|
};
|
||||||
|
|
||||||
|
export type DoToast = {
|
||||||
|
type: ACTIONS.CREATE_TOAST,
|
||||||
|
data: Toast,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Events:
|
||||||
|
- List of notifications based on user interactions/app events
|
||||||
|
- Always saved, but can be manually deleted
|
||||||
|
- Can happen in the background, or because of user interaction (ex: publish confirmed)
|
||||||
|
*/
|
||||||
|
export type Event = {
|
||||||
|
id: string, // Unique id
|
||||||
|
dateCreated: number,
|
||||||
|
isRead: boolean, // Used to display "new" notifications that a user hasn't seen yet
|
||||||
|
source?: string, // The type/area an event is from. Used for sorting (ex: publishes, transactions)
|
||||||
|
// We may want to use priority/isDismissed in the future to specify how urgent a notification is
|
||||||
|
// and if the user should see it immediately
|
||||||
|
// isDissmied: boolean,
|
||||||
|
// priority?: number
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DoEvent = {
|
||||||
|
type: ACTIONS.CREATE_EVENT,
|
||||||
|
data: Event,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DoEditEvent = {
|
||||||
|
type: ACTIONS.EDIT_EVENT,
|
||||||
|
data: {
|
||||||
|
id: string,
|
||||||
|
isRead: boolean,
|
||||||
|
// In the future we can add `isDismissed` if we decide to show notifications as they come in
|
||||||
|
// Similar to Facebook's notifications in the corner of the screen
|
||||||
|
// isDismissed: boolean,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DoDeleteEvent = {
|
||||||
|
type: ACTIONS.DELETE_EVENT,
|
||||||
|
data: {
|
||||||
|
id: string, // The id to delete
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Errors:
|
||||||
|
- First-in, first-out queue
|
||||||
|
- Errors that should interupt user behavior
|
||||||
|
- For errors that can be shown without interrupting a user, use Toast with the isError flag
|
||||||
|
*/
|
||||||
|
export type Error = {
|
||||||
|
title: string,
|
||||||
|
text: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DoError = {
|
||||||
|
type: ACTIONS.CREATE_ERROR,
|
||||||
|
data: Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DoDismissError = {
|
||||||
|
type: ACTIONS.DISMISS_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
NotificationState
|
||||||
|
*/
|
||||||
|
export type NotificationState = {
|
||||||
|
events: Array<Event>,
|
||||||
|
errors: Array<Error>,
|
||||||
|
toasts: Array<Toast>,
|
||||||
};
|
};
|
||||||
|
|
|
@ -5977,6 +5977,10 @@ uuid@^3.1.0:
|
||||||
version "3.2.1"
|
version "3.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
|
||||||
|
|
||||||
|
uuid@^3.3.2:
|
||||||
|
version "3.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
|
||||||
|
|
||||||
v8-compile-cache@^1.1.2:
|
v8-compile-cache@^1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz#8d32e4f16974654657e676e0e467a348e89b0dc4"
|
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz#8d32e4f16974654657e676e0e467a348e89b0dc4"
|
||||||
|
|
Loading…
Reference in a new issue