Skip to content

Instantly share code, notes, and snippets.

@SanskarSans
Last active July 28, 2017 12:21
Show Gist options
  • Save SanskarSans/b30c085ffacf01c58b66f128096746cc to your computer and use it in GitHub Desktop.
Save SanskarSans/b30c085ffacf01c58b66f128096746cc to your computer and use it in GitHub Desktop.
import action from "utils/action";
action is made generic which is in utils
export default function action(TYPE, ...keys) {
return (...values) => {
const axn = { type: TYPE };
// Only set the defined keys in order (others are 'undefined' automatically)
values.map((v, i) => { // eslint-disable-line array-callback-return
axn[keys[i]] = v;
});
return axn;
};
}
export const logRequest = action(LOGS_FETCH_REQUEST);
export const logFetched = action(LOGS_FETCH_SUCCESS, "logs");
export const logFetchingError = action(LOGS_FETCH_FAILURE, "error");
export const logDelete = logId => ({
type: LOG_DELETE_REQUEST,
shouldConfirm: true,
logId
});
export const logDeleted = action(LOG_DELETE_SUCCESS, "response", "logId");
export const logDeletingFailure = action(LOG_DELETE_FAILURE, "error");
export const logsDelete = action(LOGS_DELETE_REQUEST);
export const logsDeleted = action(LOGS_DELETE_SUCCESS, "response");
export const logsDeletingFailure = action(LOGS_DELETE_FAILURE, "error");
import React from 'react';
const Loader = prop => WrappedComponent => {
return class ClassLoader extends React.PureComponent {
render() {
if (this.props.isRequesting) {
return <h1>Loading...</h1>;
}
return <WrappedComponent {...this.props} />;
}
};
};
export default Loader;
import React from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
const transitionOptions = {
transitionName: 'notification-fade',
transitionEnterTimeout: 400,
transitionLeaveTimeout: 400
};
const LogList = ({ logs, ...props }) => {
return (
<div>
<ReactCSSTransitionGroup {...transitionOptions}>
{logs.map(log =>
<div className="segment" key={log._id}>
<li className="two columns grid">
<div className="column" onClick={() => props.handleDialog(log._id, log.error_stack)}>
<p>
{log.error_message}
</p>
</div>
<div className="column align-right" onClick={() => props.handleDelete(log._id)}>
<a className="negative icon button">
<i className="icon icon-trash" />{' '}
</a>
</div>
</li>
</div>
)}
</ReactCSSTransitionGroup>
</div>
);
};
export default LogList;
import React from 'react';
import { createStructuredSelector } from 'reselect';
import { connect } from 'react-redux';
import { showDialog } from 'containers/App/actions';
import { logRequest, logDelete, logsDelete } from './actions';
import { makeSelectDialog } from 'containers/App/selectors';
import { makeSelectLogs, makeSelectLoadingState } from './selectors';
import LogsDetail from './LogsDetail';
import LogList from './LogList';
import DeleteConfirmation from 'components/DeleteConfirmation';
import { isEmpty } from 'utils/helper';
import LoaderHOC from 'components/Loader';
const mapDispatchToProps = dispatch => ({
requestLogs: () => dispatch(logRequest()),
deleteLog: logId => dispatch(logDelete(logId)),
deleteLogs: () => dispatch(logsDelete()),
showDialog: dialog => dispatch(showDialog(dialog)),
hideDialog: () => dispatch(showDialog(null))
});
const mapStateToProps = createStructuredSelector({
logs: makeSelectLogs(),
isRequesting: makeSelectLoadingState(),
dialog: makeSelectDialog()
});
@LoaderHOC('isRequesting')
class Logs extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
show: false,
open: false,
loading: true
};
}
componentDidMount() {
if (this.props.logs && Object.keys(this.props.logs).length > 0) {
this.props.requestLogs();
}
}
handleDialog = (key, logs) => {
this.setState({ show: true });
const logsDetail = <LogsDetail hideDialog={this.props.hideDialog} log={logs} />;
this.props.showDialog(logsDetail);
};
handleDelete = key => {
this.setState({ show: true });
const logDeleteConfirmation = (
<DeleteConfirmation
hideDialog={this.props.hideDialog}
deleteKey={key}
onDelete={this.props.deleteLog}
text="log"
/>
);
this.props.showDialog(logDeleteConfirmation);
};
handleDeleteAllLogs = () => {
this.setState({ show: true });
const logDeleteConfirmation = (
<DeleteConfirmation
hideDialog={this.props.hideDialog}
onDelete={this.props.deleteLogs}
text="all logs"
/>
);
this.props.showDialog(logDeleteConfirmation);
};
render() {
const { logs, isRequesting } = this.props;
return (
<div className="left container">
<div className="two columns grid">
<div className="column">
<h1>Logs</h1>
</div>
<div className="column align-right">
<button className="negative button" onClick={() => this.handleDeleteAllLogs()}>
Delete All Logs
</button>
</div>
</div>
<br />
<ul className="list-group">
<LogList
logs={logs}
handleDelete={key => this.handleDelete(key)}
handleDialog={(key, errorStack) => this.handleDialog(key, errorStack)}
/>
{this.state.show ? this.props.dialog : null}
</ul>
</div>
);
}
}
// export default connect(mapStateToProps, mapDispatchToProps)(Logs);
export default connect(mapStateToProps, mapDispatchToProps)(Logs);
import { fromJS } from 'immutable';
import {
LOGS_FETCH_REQUEST,
LOGS_FETCH_SUCCESS,
LOGS_FETCH_FAILURE,
LOG_DELETE_REQUEST,
LOG_DELETE_SUCCESS,
LOG_DELETE_FAILURE,
LOGS_DELETE_REQUEST,
LOGS_DELETE_SUCCESS,
LOGS_DELETE_FAILURE
} from './constants';
const initialState = fromJS({
requesting: false,
deleted: false,
response: {},
logs: [],
error: null
});
function showLogs(state = initialState, action) {
switch (action.type) {
case LOGS_FETCH_REQUEST:
case LOG_DELETE_REQUEST:
case LOGS_DELETE_REQUEST:
return state.set('requesting', true);
case LOGS_FETCH_SUCCESS:
return state.set('requesting', false).set('logs', action.logs.data.dataList);
case LOGS_FETCH_FAILURE:
case LOG_DELETE_FAILURE:
case LOGS_DELETE_FAILURE:
return state.set('error', action.error).set('requesting', false);
case LOG_DELETE_SUCCESS:
return state
.set('deleted', true)
.set('requesting', false)
.set('response', action.response)
.set(
'logs',
state.get('logs').filter(log => {
return log._id !== action.logId[0];
})
);
case LOGS_DELETE_SUCCESS:
return state
.set('deleted', true)
.set('requesting', false)
.set('response', action.response)
.set('logs', state.get('logs').clear());
default:
return state;
}
}
export default showLogs;
import {
takeLatest,
fork,
put,
cancel,
take,
select,
call
} from "redux-saga/effects";
import {
logFetched,
logFetchingError,
logDeleted,
logDeletingError,
logsDeleted,
logsDeletingError
} from "./actions";
import {
LOGS_FETCH_REQUEST,
LOG_DELETE_REQUEST,
LOGS_DELETE_REQUEST
} from "./constants";
import { XcelTrip } from "containers/App/sagas";
import { selectLogs } from "./selectors";
const token = JSON.parse(localStorage.getItem("user"))["token"];
function* fetchLogs() {
yield call(
XcelTrip.get("api/error-logs", logFetched, logFetchingError, token)
);
}
function* deleteLog(action) {
const logId = action.logId;
yield call(
XcelTrip.delete(
`api/error-logs/${logId}`,
logDeleted,
logDeletingError,
logId
)
);
}
function* deleteLogs() {
const logs = yield select(selectLogs());
if (logs.size) {
yield call(
XcelTrip.delete(`api/error-logs/`, logsDeleted, logsDeletingError)
);
}
}
function* logWatcher() {
yield takeLatest(LOGS_FETCH_REQUEST, fetchLogs);
yield takeLatest(LOG_DELETE_REQUEST, deleteLog);
yield takeLatest(LOGS_DELETE_REQUEST, deleteLogs);
}
export default [logWatcher];
import { createSelector } from 'reselect';
export const selectLogs = state => state.get('logs');
export const makeSelectLoadingState = () =>
createSelector(selectLogs, logState => logState.get('requesting'));
export const makeSelectLogs = () => createSelector(selectLogs, logState => logState.get('logs'));
// tried this way too
const createDeepEqualSelector = createSelectorCreator(
defaultMemoize,
isEqual
);
export const selectLogs = state => state.get('logs');
export const makeSelectLogs = () => createDeepEqualSelector(selectLogs, logState => logState.get('logs'));
export const makeSelectLoadingState = () =>
createDeepEqualSelector(selectLogs, logState => logState.get('requesting'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment