From 0de7cc7309a6519ce51ebdf341875a48d9167dbb Mon Sep 17 00:00:00 2001 From: sipp11 Date: Mon, 15 Oct 2018 19:16:43 +0900 Subject: [PATCH] Basic Fare manager --- src/actions/fare.js | 10 ++- src/components/FareAttributesForm.js | 88 +++++++++++++------ src/components/FareList.js | 107 ++++++++++------------- src/components/FareRulesForm.js | 123 ++++++++++++++++++++------- src/constants/choices.js | 12 +++ src/container/Main.js | 2 + src/reducers/fareattr.js | 3 +- src/reducers/farerule.js | 3 +- src/sagas.js | 2 +- src/utils/index.js | 36 ++++++++ 10 files changed, 259 insertions(+), 127 deletions(-) diff --git a/src/actions/fare.js b/src/actions/fare.js index e05fa31..dfc53fe 100644 --- a/src/actions/fare.js +++ b/src/actions/fare.js @@ -10,11 +10,12 @@ export const getFareAttr = (query) => ({ endpoint: `${API_URL}/fare-attribute/?${query || ''}`, method: 'GET', headers: RSAAHeaders, - bailout: (state) => state.fareattr.fetching || state.fareattr.query === query, + bailout: (state) => state.fareattr.fetching || ( + state.fareattr.query !== undefined && state.fareattr.query === query), types: [ { type: types.FAREATTR_REQUEST, - meta: { query: query }, + meta: { query: query || '' }, }, types.FAREATTR_SUCCESS, types.FAREATTR_FAILURE, @@ -72,11 +73,12 @@ export const getFareRule = (query) => ({ endpoint: `${API_URL}/fare-rule/?${query || ''}`, method: 'GET', headers: RSAAHeaders, - bailout: (state) => state.fareattr.fetching || state.fareattr.query === query, + bailout: (state) => state.farerule.fetching || ( + state.farerule.query !== undefined && state.farerule.query === query), types: [ { type: types.FARERULE_REQUEST, - meta: { query: query }, + meta: { query: query || '' }, }, types.FARERULE_SUCCESS, types.FARERULE_FAILURE, diff --git a/src/components/FareAttributesForm.js b/src/components/FareAttributesForm.js index 23b7ef5..c194738 100644 --- a/src/components/FareAttributesForm.js +++ b/src/components/FareAttributesForm.js @@ -9,9 +9,14 @@ import { deleteFareAttr } from '../actions/fare' import store from '../store' -import HorizontalInput from './parts/HorizontalInput' -import HorizontalDate from './parts/HorizontalDate' -import HorizontalCheckbox from './parts/HorizontalCheckbox' +import Input from './parts/Input' +import OurSelect from './parts/Select' +import AsyncSelect from 'react-select/lib/Async' +import { components } from 'react-select' +import { + PaymentMethodChoices, TransferChoices +} from '../constants/choices' +import { getItemFromList, getAgencyAsyncSelect } from '../utils' const StyledFareAttributesForm = styled.div` padding: 1rem; @@ -19,6 +24,17 @@ background: #fafafa; `; +const AgencyOption = (props) => { + const { agency_id, name } = props.data + return ( + + {agency_id} {name} + + ) +} + + + class FareAttributesForm extends Component { state = { @@ -26,10 +42,10 @@ class FareAttributesForm extends Component { fare_id: "", price: 0, currency_type: "THB", // ISO 4217 - payment_method: "", // 0 - paid on board or 1 - paid before boarding + payment_method: "0", // 0 - paid on board or 1 - paid before boarding transfer: "0", // 0 no transfer, 1 - transfer once, 2 tranfer twice, // '' - unlimited transfer - agency_id: false, // optional + agency: null, // optional transfer_duration: "0", // optional 0 - no transfer allowed, // otherwise it's length of time in seconds before // transfer expires @@ -69,9 +85,9 @@ class FareAttributesForm extends Component { componentWillMount() { const { props } = this - const { serviceId } = props.match.params + const { attribID } = props.match.params const { results } = props.fareattr - const ones = results.filter(ele => ele.service_id === serviceId) + const ones = results.filter(ele => ele.id === +attribID) if (ones.length > 0) { this.setState(ones[0]) } @@ -84,21 +100,21 @@ class FareAttributesForm extends Component {

{one.name}  

- - - - + value={getItemFromList(one.payment_method, PaymentMethodChoices, '0')} + handleChange={this.handleChange} + choices={PaymentMethodChoices} /> - + + - {/* TODO: probably need HorizontalSelect */} - +
+ + { + if (evt.action === 'select-option') { + let evt = { + target: { + name: 'agency', + value: resp, + }} + this.handleChange(evt) + } + }} + /> +
- props.checked ? 'green' : 'gray'};; -` - const FakeRow = styled.nav` padding-top: 5px; padding-bottom: 5px; @@ -24,20 +23,15 @@ background: white; margin-bottom: 1rem; ` - -const CheckboxIcon = (props) => ( - - {props.checked === true && } - {props.checked !== true && } - -) - class FareList extends Component { componentWillMount() { - const { count } = this.props.fareattr - if (count === 0) - store.dispatch(getCalendar()) + const { fareattr, farerule } = this.props + if (fareattr.count === 0) + store.dispatch(getFareAttr()) + + if (farerule.count === 0) + store.dispatch(getFareRule()) } render() { @@ -47,105 +41,94 @@ class FareList extends Component {

Fare

+
- {fareattr.results && Object.keys(farerule.results).map(i => ( + {fareattr.results && Object.keys(fareattr.results).map(i => (

Fare ID

-

{fareattr.results[i].fare_id}

+

{fareattr.results[i].fare_id}

-

Origin ID

-

{fareattr.results[i].origin_id}

+

Price

+

{fareattr.results[i].price} + {fareattr.results[i].currency_type} +
+ {getItemFromList(fareattr.results[i].payment_method, PaymentMethodChoices, '') && getItemFromList(fareattr.results[i].payment_method, PaymentMethodChoices, '').label} +

-

Destination ID (or contains)

-

- {fareattr.results[i].destination_id} - {fareattr.results[i].contains_id} -

+

Transfer / sec

+

+ {getItemFromList(fareattr.results[i].transfer, TransferChoices, '') && getItemFromList(fareattr.results[i].transfer, TransferChoices, '').label} + / {fareattr.results[i].transfer_duration}

-

Route ID

-

- {fareattr.results[i].route_id} -

+

Agency

+

{fareattr.results[i].agency.name}

))}
-
- {fareattr.results && Object.keys(fareattr.results).map(i => ( - + {farerule.results && Object.keys(farerule.results).map(i => ( +

Fare ID

-

{fareattr.results[i].fare_id}

+

{farerule.results[i].fare.fare_id}

-

Price

-

{fareattr.results[i].price}

-
-
-
-
-

Currency

-

{fareattr.results[i].currency_type}

-
-
-
-
-

Payment Method

-

{fareattr.results[i].payment_method}

-
-
-
-
-

Transfer

-

{fareattr.results[i].transfer}

+

Origin ID

+

{farerule.results[i].origin_id}

-

Duration

-

{fareattr.results[i].transfer_duration}

+

Destination ID (or contains)

+

+ {farerule.results[i].destination_id} + {farerule.results[i].contains_id} +

-

Agency

-

{fareattr.results[i].agency_id}

+

Route ID

+

+ {farerule.results[i].route_id} +

))}
+
) diff --git a/src/components/FareRulesForm.js b/src/components/FareRulesForm.js index 8641948..4f211ab 100644 --- a/src/components/FareRulesForm.js +++ b/src/components/FareRulesForm.js @@ -9,15 +9,34 @@ import { deleteFareRule } from '../actions/fare' import store from '../store' -import HorizontalInput from './parts/HorizontalInput' -import HorizontalDate from './parts/HorizontalDate' -import HorizontalCheckbox from './parts/HorizontalCheckbox' +import Input from './parts/Input' +import AsyncSelect from 'react-select/lib/Async' +import { components } from 'react-select' +import { getStopsAsyncSelect, getFareAttrAsyncSelect } from '../utils' const StyledFareRulesForm = styled.div` padding: 1rem; background: #fafafa; `; +const StopOption = (props) => { + const { stop_id, name } = props.data + return ( + + {stop_id} {name} + + ) +} + +const FareAttrOption = (props) => { + const { fare_id, price, currency_type } = props.data + return ( + + {fare_id} {price} {currency_type} + + ) +} + class FareRulesForm extends Component { @@ -64,9 +83,10 @@ class FareRulesForm extends Component { componentWillMount() { const { props } = this - const { serviceId } = props.match.params + const { ruleID } = props.match.params const { results } = props.farerule - const ones = results.filter(ele => ele.service_id === serviceId) + + const ones = results.filter(ele => ele.id === +ruleID) if (ones.length > 0) { this.setState(ones[0]) } @@ -79,35 +99,78 @@ class FareRulesForm extends Component {

{one.name}  

- - + + { + if (evt.action === 'select-option') { + let evt = { + target: { + name: 'fare', + value: resp, + }} + this.handleChange(evt) + } + }} + /> +
+ + - +
+ + { + if (evt.action === 'select-option') { + let evt = { + target: { + name: 'origin_id', + value: resp.stop_id, + }} + this.handleChange(evt) + } + }} + /> +
- +
+ + { + if (evt.action === 'select-option') { + let evt = { + target: { + name: 'destination_id', + value: resp.stop_id, + }} + this.handleChange(evt) + } + }} + /> +
-
}
- Cancel + Cancel
@@ -145,17 +208,17 @@ class FareRulesForm extends Component { // this is a create form if (serviceId === undefined) { if (one.justSubmit === true && !fetching) { - return + return } return this.renderForm() } if (one.id === null && serviceId.length > 0) - return + return // redirect to fare list if submitted if (one.justSubmit === true && !fetching) { - return + return } return this.renderForm() } @@ -164,7 +227,7 @@ class FareRulesForm extends Component { const mapStateToProps = state => ({ - farerule: state.farerule + farerule: state.farerule, }) const connectFareRulesForm = connect( diff --git a/src/constants/choices.js b/src/constants/choices.js index 583d483..2c2bdc4 100644 --- a/src/constants/choices.js +++ b/src/constants/choices.js @@ -62,3 +62,15 @@ export const ExactTimeChoices = [ { value: '0', label: 'Not exactly scheduled.' }, { value: '1', label: 'Exactly scheduled' }, ] + +export const PaymentMethodChoices = [ + { value: '0', label: 'Paid on board' }, + { value: '1', label: 'Paid before boarding' }, +] + +export const TransferChoices = [ + { value: '0', label: 'No transfer' }, + { value: '1', label: 'Transfer once' }, + { value: '2', label: 'Transfer twice' }, + { value: '', label: 'Unlimited transfer' }, +] diff --git a/src/container/Main.js b/src/container/Main.js index 3b9cd2f..0e87455 100644 --- a/src/container/Main.js +++ b/src/container/Main.js @@ -55,7 +55,9 @@ class Main extends Component { + + diff --git a/src/reducers/fareattr.js b/src/reducers/fareattr.js index 6b5ecd9..4d36700 100644 --- a/src/reducers/fareattr.js +++ b/src/reducers/fareattr.js @@ -14,11 +14,10 @@ const fareAttrInitState = { const fareAttr = (state = fareAttrInitState, action) => { switch(action.type) { case FAREATTR_REQUEST: - const { query } = action.meta return { ...state, fetching: true, - query, + query: action.meta !== undefined ? action.meta.query : state.query, } case FAREATTR_SUCCESS: const { count, next, prev, results } = action.payload diff --git a/src/reducers/farerule.js b/src/reducers/farerule.js index fd631c1..7421eee 100644 --- a/src/reducers/farerule.js +++ b/src/reducers/farerule.js @@ -14,11 +14,10 @@ const fareRuleInitState = { const fareRule = (state = fareRuleInitState, action) => { switch(action.type) { case FARERULE_REQUEST: - const { query } = action.meta return { ...state, fetching: true, - query, + query: action.meta !== undefined ? action.meta.query : state.query, } case FARERULE_SUCCESS: const { count, next, prev, results } = action.payload diff --git a/src/sagas.js b/src/sagas.js index 1073acb..ec3bd95 100644 --- a/src/sagas.js +++ b/src/sagas.js @@ -1,4 +1,4 @@ -import { call, put, takeEvery, takeLatest } from 'redux-saga/effects' +import { call, put, takeLatest } from 'redux-saga/effects' // takeEvery import { apiClient } from './utils/ApiClient' import * as types from './constants/ActionTypes' diff --git a/src/utils/index.js b/src/utils/index.js index f505cfe..c418295 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -31,3 +31,39 @@ export const getStopsAsyncSelect = (inputValue, callback) => { }))) }) } + + +export const getFareAttrAsyncSelect = (inputValue, callback) => { + const that = this + const cancelToken = new CancelToken(function executor(c) { + // An executor function receives a cancel function as a parameter + if (that.cancel) + that.cancel() + that.cancel = c + }) + apiClient(`/fare-attribute/?search=${inputValue}`, { cancelToken }) + .then((resp) => { + callback(resp.data.results.map(i => ({ + ...i, + label: i.fare_id + }))) + }) +} + + +export const getAgencyAsyncSelect = (inputValue, callback) => { + const that = this + const cancelToken = new CancelToken(function executor(c) { + // An executor function receives a cancel function as a parameter + if (that.cancel) + that.cancel() + that.cancel = c + }) + apiClient(`/agency/?search=${inputValue}`, { cancelToken }) + .then((resp) => { + callback(resp.data.results.map(i => ({ + ...i, + label: i.name + }))) + }) +}