mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-31 02:26:50 +10:00
sdk.transactions.transition accept call + accept button
This commit is contained in:
parent
4c7c0bcd86
commit
efb5f0ee6e
6 changed files with 72 additions and 5 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
|
.actionButtons,
|
||||||
.title {
|
.title {
|
||||||
margin: 1rem 1rem 2rem 1rem;
|
margin: 1rem 1rem 2rem 1rem;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,26 @@ import { types } from '../../util/sdkLoader';
|
||||||
import { addEntities } from '../../ducks/sdk.duck';
|
import { addEntities } from '../../ducks/sdk.duck';
|
||||||
import { fetchCurrentUser } from '../../ducks/user.duck';
|
import { fetchCurrentUser } from '../../ducks/user.duck';
|
||||||
|
|
||||||
|
// Transition-to keys
|
||||||
|
const TRANSITION_ACCEPT = 'transition/accept';
|
||||||
|
|
||||||
// ================ Action types ================ //
|
// ================ Action types ================ //
|
||||||
|
|
||||||
export const FETCH_SALE_REQUEST = 'app/InboxPage/FETCH_SALE_REQUEST';
|
export const FETCH_SALE_REQUEST = 'app/InboxPage/FETCH_SALE_REQUEST';
|
||||||
export const FETCH_SALE_SUCCESS = 'app/InboxPage/FETCH_SALE_SUCCESS';
|
export const FETCH_SALE_SUCCESS = 'app/InboxPage/FETCH_SALE_SUCCESS';
|
||||||
export const FETCH_SALE_ERROR = 'app/InboxPage/FETCH_SALE_ERROR';
|
export const FETCH_SALE_ERROR = 'app/InboxPage/FETCH_SALE_ERROR';
|
||||||
|
|
||||||
|
export const ACCEPT_SALE_REQUEST = 'app/InboxPage/ACCEPT_SALE_REQUEST';
|
||||||
|
export const ACCEPT_SALE_SUCCESS = 'app/InboxPage/ACCEPT_SALE_SUCCESS';
|
||||||
|
export const ACCEPT_SALE_ERROR = 'app/InboxPage/ACCEPT_SALE_ERROR';
|
||||||
// ================ Reducer ================ //
|
// ================ Reducer ================ //
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
fetchInProgress: false,
|
fetchInProgress: false,
|
||||||
fetchSaleError: null,
|
fetchSaleError: null,
|
||||||
transactionRef: null,
|
transactionRef: null,
|
||||||
|
acceptOrRejectInProgress: false,
|
||||||
|
acceptSaleError: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function checkoutPageReducer(state = initialState, action = {}) {
|
export default function checkoutPageReducer(state = initialState, action = {}) {
|
||||||
|
|
@ -29,6 +37,14 @@ export default function checkoutPageReducer(state = initialState, action = {}) {
|
||||||
console.error(payload); // eslint-disable-line
|
console.error(payload); // eslint-disable-line
|
||||||
return { ...state, fetchInProgress: false, fetchSaleError: payload };
|
return { ...state, fetchInProgress: false, fetchSaleError: payload };
|
||||||
|
|
||||||
|
case ACCEPT_SALE_REQUEST:
|
||||||
|
return { ...state, acceptOrRejectInProgress: true, acceptSaleError: null };
|
||||||
|
case ACCEPT_SALE_SUCCESS:
|
||||||
|
return { ...state, acceptOrRejectInProgress: false };
|
||||||
|
case ACCEPT_SALE_ERROR:
|
||||||
|
console.error(payload); // eslint-disable-line
|
||||||
|
return { ...state, acceptOrRejectInProgress: false, acceptSaleError: payload };
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
@ -40,6 +56,10 @@ const fetchSaleRequest = () => ({ type: FETCH_SALE_REQUEST });
|
||||||
const fetchSaleSuccess = response => ({ type: FETCH_SALE_SUCCESS, payload: response });
|
const fetchSaleSuccess = response => ({ type: FETCH_SALE_SUCCESS, payload: response });
|
||||||
const fetchSaleError = e => ({ type: FETCH_SALE_ERROR, error: true, payload: e });
|
const fetchSaleError = e => ({ type: FETCH_SALE_ERROR, error: true, payload: e });
|
||||||
|
|
||||||
|
const acceptSaleRequest = () => ({ type: ACCEPT_SALE_REQUEST });
|
||||||
|
const acceptSaleSuccess = () => ({ type: ACCEPT_SALE_SUCCESS });
|
||||||
|
const acceptSaleError = e => ({ type: ACCEPT_SALE_ERROR, error: true, payload: e });
|
||||||
|
|
||||||
// ================ Thunks ================ //
|
// ================ Thunks ================ //
|
||||||
|
|
||||||
export const fetchSale = id =>
|
export const fetchSale = id =>
|
||||||
|
|
@ -59,6 +79,23 @@ export const fetchSale = id =>
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const acceptSale = id =>
|
||||||
|
(dispatch, getState, sdk) => {
|
||||||
|
dispatch(acceptSaleRequest());
|
||||||
|
|
||||||
|
return sdk.transactions
|
||||||
|
.transition({ id, transition: TRANSITION_ACCEPT, params: {} }, { expand: true })
|
||||||
|
.then(response => {
|
||||||
|
dispatch(addEntities(response));
|
||||||
|
dispatch(acceptSaleSuccess());
|
||||||
|
return response;
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
dispatch(acceptSaleError(e));
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// loadData is a collection of async calls that need to be made
|
// loadData is a collection of async calls that need to be made
|
||||||
// before page has all the info it needs to render itself
|
// before page has all the info it needs to render itself
|
||||||
export const loadData = params =>
|
export const loadData = params =>
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@ import { FormattedMessage, intlShape, injectIntl } from 'react-intl';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import * as propTypes from '../../util/propTypes';
|
import * as propTypes from '../../util/propTypes';
|
||||||
import { ensureBooking, ensureListing, ensureTransaction, ensureUser } from '../../util/data';
|
import { ensureBooking, ensureListing, ensureTransaction, ensureUser } from '../../util/data';
|
||||||
import { SaleDetailsPanel, PageLayout } from '../../components';
|
import { Button, SaleDetailsPanel, PageLayout } from '../../components';
|
||||||
import { getEntities } from '../../ducks/sdk.duck';
|
import { getEntities } from '../../ducks/sdk.duck';
|
||||||
import { loadData } from './SalePage.duck';
|
import { acceptSale, loadData } from './SalePage.duck';
|
||||||
|
|
||||||
import css from './SalePage.css';
|
import css from './SalePage.css';
|
||||||
|
|
||||||
// SalePage handles data loading
|
// SalePage handles data loading
|
||||||
// It show loading data text or SaleDetailsPanel (and later also another panel for messages).
|
// It show loading data text or SaleDetailsPanel (and later also another panel for messages).
|
||||||
export const SalePageComponent = props => {
|
export const SalePageComponent = props => {
|
||||||
const { intl, transaction } = props;
|
const { intl, onAcceptSale, transaction } = props;
|
||||||
const currentTransaction = ensureTransaction(transaction);
|
const currentTransaction = ensureTransaction(transaction);
|
||||||
const currentListing = ensureListing(currentTransaction.listing);
|
const currentListing = ensureListing(currentTransaction.listing);
|
||||||
const title = currentListing.attributes.title;
|
const title = currentListing.attributes.title;
|
||||||
|
|
@ -22,6 +22,7 @@ export const SalePageComponent = props => {
|
||||||
subtotalPrice: currentTransaction.attributes.total,
|
subtotalPrice: currentTransaction.attributes.total,
|
||||||
commission: currentTransaction.attributes.commission,
|
commission: currentTransaction.attributes.commission,
|
||||||
saleState: currentTransaction.attributes.state,
|
saleState: currentTransaction.attributes.state,
|
||||||
|
lastTransitionedAt: currentTransaction.attributes.lastTransitionedAt,
|
||||||
listing: currentListing,
|
listing: currentListing,
|
||||||
booking: ensureBooking(currentTransaction.booking),
|
booking: ensureBooking(currentTransaction.booking),
|
||||||
customer: ensureUser(currentTransaction.customer),
|
customer: ensureUser(currentTransaction.customer),
|
||||||
|
|
@ -35,19 +36,29 @@ export const SalePageComponent = props => {
|
||||||
? <SaleDetailsPanel className={detailsClassName} {...detailsProps} />
|
? <SaleDetailsPanel className={detailsClassName} {...detailsProps} />
|
||||||
: <h1 className={css.title}><FormattedMessage id="SalePage.loadingData" /></h1>;
|
: <h1 className={css.title}><FormattedMessage id="SalePage.loadingData" /></h1>;
|
||||||
|
|
||||||
|
const actionButtons = currentTransaction.attributes.state === propTypes.TX_STATE_PREAUTHORIZED
|
||||||
|
? <div className={css.actionButtons}>
|
||||||
|
<Button onClick={() => onAcceptSale(currentTransaction.id)}>
|
||||||
|
<FormattedMessage id="SalePage.acceptButton" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayout title={intl.formatMessage({ id: 'SalePage.title' }, { title })}>
|
<PageLayout title={intl.formatMessage({ id: 'SalePage.title' }, { title })}>
|
||||||
{panel}
|
{panel}
|
||||||
|
{actionButtons}
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
SalePageComponent.defaultProps = { transaction: null };
|
SalePageComponent.defaultProps = { transaction: null };
|
||||||
|
|
||||||
const { oneOf } = PropTypes;
|
const { func, oneOf } = PropTypes;
|
||||||
|
|
||||||
SalePageComponent.propTypes = {
|
SalePageComponent.propTypes = {
|
||||||
intl: intlShape.isRequired,
|
intl: intlShape.isRequired,
|
||||||
|
onAcceptSale: func.isRequired,
|
||||||
tab: oneOf(['details', 'discussion']).isRequired,
|
tab: oneOf(['details', 'discussion']).isRequired,
|
||||||
transaction: propTypes.transaction,
|
transaction: propTypes.transaction,
|
||||||
};
|
};
|
||||||
|
|
@ -63,7 +74,13 @@ const mapStateToProps = state => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const SalePage = connect(mapStateToProps)(injectIntl(SalePageComponent));
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
onAcceptSale: transactionId => dispatch(acceptSale(transactionId)),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const SalePage = connect(mapStateToProps, mapDispatchToProps)(injectIntl(SalePageComponent));
|
||||||
|
|
||||||
SalePage.loadData = params => {
|
SalePage.loadData = params => {
|
||||||
return loadData(params);
|
return loadData(params);
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ describe('SalePage', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
|
onAcceptSale: () => {},
|
||||||
transaction,
|
transaction,
|
||||||
tab: 'details',
|
tab: 'details',
|
||||||
intl: fakeIntl,
|
intl: fakeIntl,
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ exports[`SalePage matches snapshot 1`] = `
|
||||||
"type": "user",
|
"type": "user",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lastTransitionedAt={2017-06-01T00:00:00.000Z}
|
||||||
listing={
|
listing={
|
||||||
Object {
|
Object {
|
||||||
"attributes": Object {
|
"attributes": Object {
|
||||||
|
|
@ -65,5 +66,14 @@ exports[`SalePage matches snapshot 1`] = `
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
}
|
}
|
||||||
} />
|
} />
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
className={null}
|
||||||
|
onClick={[Function]}>
|
||||||
|
<FormattedMessage
|
||||||
|
id="SalePage.acceptButton"
|
||||||
|
values={Object {}} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</Connect(withRouter(PageLayout))>
|
</Connect(withRouter(PageLayout))>
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@
|
||||||
"PaginationLinks.next": "Next page",
|
"PaginationLinks.next": "Next page",
|
||||||
"SaleDetailsPanel.listingTitle": "{customerName} has requested to book {title}.",
|
"SaleDetailsPanel.listingTitle": "{customerName} has requested to book {title}.",
|
||||||
"SaleDetailsPanel.saleStatusMessage": "{customerName} is waiting for your response.",
|
"SaleDetailsPanel.saleStatusMessage": "{customerName} is waiting for your response.",
|
||||||
|
"SalePage.acceptButton": "Accept",
|
||||||
"SalePage.loadingData": "Loading sale data.",
|
"SalePage.loadingData": "Loading sale data.",
|
||||||
"SalePage.title": "Sale details for ${title}.",
|
"SalePage.title": "Sale details for ${title}.",
|
||||||
"SearchPage.foundResults": "{count, number} {count, plural, one {listing} other {listings}} found.",
|
"SearchPage.foundResults": "{count, number} {count, plural, one {listing} other {listings}} found.",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue