Browse Source

Merge pull request #119 from SuperNETorg/multiple-toasts

Toaster component - enable multiple toasts
all-modes
pbca26 8 years ago
committed by GitHub
parent
commit
0fc448fddc
  1. 32
      react/src/actions/actionCreators.js
  2. 3
      react/src/actions/storeType.js
  3. 3
      react/src/actions/walletAuth.js
  4. 79
      react/src/components/toaster/toaster-item.js
  5. 78
      react/src/components/toaster/toaster.js
  6. 27
      react/src/reducers/toaster.js

32
react/src/actions/actionCreators.js

@ -51,16 +51,6 @@ try {
Config = _config;
}
export function triggerToaster(display, message, title, _type) {
return {
type: storeType.TOASTER_MESSAGE,
display,
message,
title,
_type,
}
}
export function changeActiveAddress(address) {
return {
type: storeType.DASHBOARD_ACTIVE_ADDRESS,
@ -176,6 +166,24 @@ export function toggleSendReceiveCoinFormsState() {
}
}
export function triggerToaster(display, message, title, _type) {
return {
type: storeType.ADD_TOASTER_MESSAGE,
display,
message,
title,
_type,
}
}
// triggers removing of the toast with the provided toastId
export function dismissToaster(toastId) {
return {
type: storeType.REMOVE_TOASTER_MESSAGE,
toastId: toastId
}
}
export function toggleAddcoinModalState(display, isLogin) {
return {
type: storeType.DISPLAY_ADDCOIN_MODAL,
@ -250,9 +258,9 @@ export function toggleAddcoinModal(display, isLogin) {
}
}
export function dismissToasterMessage() {
export function dismissToasterMessage(toastId) {
return dispatch => {
dispatch(triggerToaster(false))
dispatch(dismissToaster(toastId))
}
}

3
react/src/actions/storeType.js

@ -1,4 +1,5 @@
export const TOASTER_MESSAGE = 'TOASTER_MESSAGE';
export const ADD_TOASTER_MESSAGE = 'ADD_TOASTER_MESSAGE';
export const REMOVE_TOASTER_MESSAGE = 'REMOVE_TOASTER_MESSAGE';
export const DISPLAY_ADDCOIN_MODAL = 'DISPLAY_ADDCOIN_MODAL';
export const GET_ACTIVE_COINS = 'GET_ACTIVE_COINS';
export const LOGIN = 'LOGIN';

3
react/src/actions/walletAuth.js

@ -3,7 +3,8 @@ import { translate } from '../translate/translate';
import {
triggerToaster,
Config,
getMainAddressState
getMainAddressState,
updateErrosStack
} from './actionCreators';
import {
logGuiHttp,

79
react/src/components/toaster/toaster-item.js

@ -0,0 +1,79 @@
import React from "react";
import {dismissToasterMessage} from "../../actions/actionCreators";
import Store from "../../store";
// each toast will be displayed for 5 seconds
const DISPLAY_LENGTH_MILLIS = 5000;
/**
* Displays one toast message
* each messages has a type, title and a content message
*/
class ToasterItem extends React.Component {
constructor(props) {
super(props);
this.state = {
display: false,
message: null,
type: null,
title: null
};
this.dismissToast = this.dismissToast.bind(this);
this.timeoutHandler = null;
}
componentWillReceiveProps(props) {
if (props &&
props.message &&
props.display) {
this.setState({
message: props.message,
display: props.display,
type: props._type,
title: props.title,
toastId: props.toastId
});
} else {
this.setState({
display: false,
message: null,
type: null,
title: null,
toastId: null
});
}
}
dismissToast(toastId) {
Store.dispatch(dismissToasterMessage(toastId));
}
renderToast() {
// ensure that setTimeout is called only once for each toast message
if (!this.timeoutHandler) {
this.timeoutHandler = setTimeout(() => {
this.dismissToast(this.state.toastId);
}, DISPLAY_LENGTH_MILLIS);
}
return (
<div className={ 'toast toast-' + this.state.type }>
<button className="toast-close-button" role="button"
onClick={ () => this.dismissToast(this.state.toastId) }>×
</button>
<div className="toast-title">{ this.state.title }</div>
<div className="toast-message">{ this.state.message }</div>
</div>
);
}
render() {
return (this.state.message && this.state.display) ?
this.renderToast() : null;
}
}
export default ToasterItem;

78
react/src/components/toaster/toaster.js

@ -1,70 +1,60 @@
import React from 'react';
import { dismissToasterMessage } from '../../actions/actionCreators';
import Store from '../../store';
import React from "react";
import {dismissToasterMessage} from "../../actions/actionCreators";
import Store from "../../store";
import ToasterItem from "./toaster-item";
/**
* Container component used for creating multiple toasts
*/
class Toaster extends React.Component {
constructor(props) {
super(props);
this.state = {
display: false,
message: null,
type: null,
title: null,
toasts: []
};
this.dismissToast = this.dismissToast.bind(this);
this.toastId = 0;
}
componentWillReceiveProps(props) {
if (props &&
props.message &&
props.display) {
props.toasts) {
this.setState({
message: props.message,
display: props.display,
type: props.type,
title: props.title,
toasts: props.toasts,
toastId: props.toasts.length
});
} else {
this.setState({
display: false,
message: null,
type: null,
title: null,
toasts: [],
toastId: 0
});
}
}
dismissToast() {
Store.dispatch(dismissToasterMessage());
dismissToast(toastId) {
Store.dispatch(dismissToasterMessage(toastId));
}
// TODO: multiple toasts
renderToast() {
setTimeout(() => {
Store.dispatch(dismissToasterMessage());
}, 5000);
// render all current toasts
render() {
return (
<div className="toaster">
<div
id="toast-container"
className="single-toast toast-bottom-right"
aria-live="polite"
role="alert">
<div className={ 'toast toast-' + this.state.type }>
<button className="toast-close-button" role="button" onClick={ this.dismissToast }>×</button>
<div className="toast-title">{ this.state.title }</div>
<div className="toast-message">{ this.state.message }</div>
</div>
</div>
<div id="toast-container"
className="single-toast toast-bottom-right"
aria-live="polite"
role="alert">
{this.state.toasts
.map((toast) => {
// sets the toastId for all new toasts
if (!toast.toastId) {
toast.toastId = this.toastId++;
}
return (
<ToasterItem key={toast.toastId} {...toast} />
);
})}
</div>
);
}
render() {
return (this.state.message && this.state.display) ?
this.renderToast() : null;
}
}
export default Toaster;
export default Toaster;

27
react/src/reducers/toaster.js

@ -1,21 +1,24 @@
import {
TOASTER_MESSAGE
ADD_TOASTER_MESSAGE,
REMOVE_TOASTER_MESSAGE
} from '../actions/storeType';
export function toaster(state = {
display: false,
message: null,
title: null,
type: null,
toasts: [],
}, action) {
if (state === null) state = {toasts: []};
switch (action.type) {
case TOASTER_MESSAGE:
return Object.assign({}, state, {
display: action.display,
message: action.message,
title: action.title,
type: action._type,
});
case ADD_TOASTER_MESSAGE:
return {
...state,
toasts: [...state.toasts, action]
};
case REMOVE_TOASTER_MESSAGE:
// filter out the toastId that should be removed
return {
...state,
toasts: state.toasts.filter(t => t.toastId !== action.toastId)
};
default:
return state;
}

Loading…
Cancel
Save