Untitled
unknown
plain_text
4 years ago
37 kB
5
Indexable
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import Cookie from 'isomorphic-cookie';
import Card from '@material-ui/core/Card';
import isEmpty from 'lodash/isEmpty';
import get from 'lodash/get';
import uniq from 'lodash/uniq';
import cloneDeep from 'lodash/cloneDeep';
import uniqBy from 'lodash/uniqBy';
import startCase from 'lodash/startCase';
import {
FORM_DATA_SCHEMA,
VALIDATION_TYPE,
ALERT_TYPE,
OPTION_RELATION_OPERATORS,
OPTION_TIME_FRAME,
OPTION_PAX_TYPE,
OPTION_CABIN_CLASS,
DEFAULT_USERLANG,
OPTION_REFUND_TYPE,
OPTION_REFUND_METHOD
} from '../../core/constants';
import { setData, url as urlHelper } from '../../helpers';
import { setAlert, actionSetLoading } from '../../redux/actions';
import { getAllSupplier } from '../../models/supplier';
import { getAllAirlines } from '../../models/airlines';
import { getAllAirports } from '../../models/airport';
import { getAllCountries } from '../../models/country';
import {
getAllReason,
getRefundDetailByReasonId
} from '../../models/refundReason';
import {
getRefundMatrixById,
addRefundMatrix,
editRefundMatrix,
validateFormula
} from '../../models/refundMatrix';
import { Head, Submit } from './../../components/Form';
import Validator from '../../components/Validator';
import TixField from '../../components/TixField';
import { Wrapper, WrapperContent } from '../../components/Wrapper/index.js';
import Select from '../../components/Select';
import InputTag from '../../components/InputTag';
import MatrixCalculator from '../../components/MatrixCalculator';
import { TixDatePicker } from '../../components/Picker';
import { select as selectHelper } from '../../helpers';
import { getAmadeusCredentialById } from '../../models/amadeusCredential';
export class Form extends Component {
constructor(props) {
super(props);
this.state = {
formData: {
supplierCode: {
[FORM_DATA_SCHEMA.value]: '',
[VALIDATION_TYPE.required]: true
},
supplierType: {
[FORM_DATA_SCHEMA.value]: '',
[VALIDATION_TYPE.required]: true
},
supplierName: {
[FORM_DATA_SCHEMA.value]: '',
[VALIDATION_TYPE.required]: true
},
currency: {
[FORM_DATA_SCHEMA.value]: '',
[VALIDATION_TYPE.required]: true
},
username: {
[FORM_DATA_SCHEMA.value]: '',
[VALIDATION_TYPE.required]: true
},
password: {
[FORM_DATA_SCHEMA.value]: '',
[VALIDATION_TYPE.required]: true
},
wsap: {
[FORM_DATA_SCHEMA.value]: '',
[VALIDATION_TYPE.required]: true
},
dutyCode: {
[FORM_DATA_SCHEMA.value]: '',
[VALIDATION_TYPE.required]: true
},
officeId: {
[FORM_DATA_SCHEMA.value]: '',
[VALIDATION_TYPE.required]: true
},
promoCodes: {
[FORM_DATA_SCHEMA.value]: '',
[VALIDATION_TYPE.required]: false
},
airlineCodes: {
[FORM_DATA_SCHEMA.value]: '',
[VALIDATION_TYPE.required]: true
},
additionalData: {}
},
url: '/amadeus-credential',
dataAllAirlines: []
};
}
componentDidMount() {
this.handleFetches();
}
handleFetches = () => {
const arr = [getAllAirlines()];
this.props.actionSetLoading(true);
const paramsId = this.props.match.params.id;
/* istanbul ignore else */
if (paramsId) {
arr.push(getAmadeusCredentialById(paramsId));
}
Promise.all(arr)
.then(values => {
const { url, currentPage } = this.state;
let dataAllAirlines = [];
const [resAllAirlines] = values;
// Airlines
if (resAllAirlines.code === 'SUCCESS') {
dataAllAirlines = selectHelper.setOptions({
data: resAllAirlines.data,
labelBy: 'name',
valueBy: 'code'
});
dataAllAirlines.push({ label: '*', value: '*' });
} else {
urlHelper.redirectPage(
this,
resAllAirlines,
ALERT_TYPE.error,
`${url}?page=${currentPage}`
);
}
// Get By Id
/* istanbul ignore else */
if (paramsId) {
const resFormData = get(values, '[1]', {});
if (resFormData.code === 'SUCCESS') {
this.setFormData(resFormData.data);
} else {
urlHelper.redirectPage(
this,
resFormData,
ALERT_TYPE.error,
`${url}?page=${currentPage}`
);
}
}
this.setState({
dataAllAirlines
});
})
.catch(err => {
this.props.setAlert({
message: err.message,
alertType: ALERT_TYPE.error
});
})
.finally(() => {
this.props.actionSetLoading(false);
});
};
handlePopulateReasonDetail = async (reasonId, handleChange, e) => {
const { tempReasonId } = this.state;
let selectedReason = [];
// Set loading to false
this.setState({ reasonLoading: false });
if (!reasonId.includes('*')) {
selectedReason = reasonId;
this.setState({ dataReasonId: tempReasonId });
} else {
selectedReason = ['*'];
this.setState({ dataReasonId: [{ label: '*', value: '*' }] });
}
if (handleChange && e) {
if (!isEmpty(e.target.value)) this.setState({ reasonLoading: true });
handleChange(e);
}
try {
const responses = await Promise.all(
selectedReason.map(reasonId => {
return getRefundDetailByReasonId(reasonId);
})
);
const reducer = (acc, curr) => {
if (curr.code === 'SUCCESS') {
curr.data
.filter(row => row.lang === this.state.lang)
.map(row => {
acc.push(startCase(row.content));
});
}
return acc;
};
const result = uniq(responses.reduce(reducer, []));
this.setState({ reasonLoading: false, dataReasonDetail: result });
} catch (e) {
console.error(e.message);
}
};
handleFetchReason = (airlineCode, resReasonId) => {
this.props.actionSetLoading(true);
getAllReason(airlineCode)
.then(res => {
let dataReasonId = [];
if (res.code === 'SUCCESS') {
const dataReasonIdTemp =
selectHelper
.setOptions({
data: res.data,
customLabel: this.customLabelReason,
valueBy: 'reasonId'
})
.filter(item => item.lang === this.state.lang) || [];
dataReasonId = uniqBy(dataReasonIdTemp, 'reasonId');
dataReasonId.push({ label: '*', value: '*' });
} else {
this.props.setAlert({
message: res.message || res.code,
alertType: ALERT_TYPE.error
});
}
this.setState(
{
tempReasonId: dataReasonId,
dataReasonId
},
() => {
// Populate after fetch reason Id
if (resReasonId) this.handlePopulateReasonDetail(resReasonId);
}
);
})
.catch(err => {
this.props.setAlert({
message: err.message,
alertType: ALERT_TYPE.error
});
})
.finally(() => {
this.props.actionSetLoading(false);
});
};
customLabelReason = data => {
return `${data.content} v${data.reasonVersion}`;
};
handleChangeDate = (e, setError, dateFrom, dateTo) => {
this.setState(
{
[`${e.target.name}Temp`]: e.target.value
},
() => {
this.validationDate(setError, dateFrom, dateTo);
}
);
};
validationDate = (setError, dateFrom, dateTo) => {
const dateFromTemp = this.state[`${dateFrom}Temp`];
const dateToTemp = this.state[`${dateTo}Temp`];
const errorDate = this.state.errorDate;
if ((!dateFromTemp && dateToTemp) || (dateFromTemp && !dateToTemp)) {
setError(dateFrom, errorDate);
setError(dateTo, errorDate);
} else {
setError(dateFrom, '');
setError(dateTo, '');
}
};
handleSubmit = ({ isError, data }) => {
/* istanbul ignore else */
if (!isError) {
const { url } = this.state;
this.props.actionSetLoading(true);
addRefundMatrix(data)
.then(res => {
if (res.code === 'SUCCESS') {
urlHelper.redirectPage(this, res, ALERT_TYPE.success, url);
} else {
this.props.setAlert({
message: res.message || res.code,
alertType: ALERT_TYPE.error
});
}
})
.catch(err => {
this.props.setAlert({
message: err.message,
alertType: ALERT_TYPE.error
});
})
.finally(() => {
this.props.actionSetLoading(false);
});
}
};
handleEdit = ({ isError, data }) => {
/* istanbul ignore else */
if (!isError) {
const paramData = {
...data
};
delete paramData.reasonContent;
delete paramData.reasonDetailContent;
const { url, currentPage } = this.state;
this.props.actionSetLoading(true);
editRefundMatrix(this.props.match.params.id, paramData)
.then(res => {
if (res.code === 'SUCCESS') {
urlHelper.redirectPage(
this,
res,
ALERT_TYPE.success,
`${url}?page=${currentPage}`
);
} else {
this.props.setAlert({
message: res.message || res.code,
alertType: ALERT_TYPE.error
});
}
})
.catch(err => {
this.props.setAlert({
message: err.message,
alertType: ALERT_TYPE.error
});
})
.finally(() => {
this.props.actionSetLoading(false);
});
}
};
setFormData = data => {
const formData = setData(data, this.state.formData);
this.setState({
formData
});
};
handleFormulaChange = (value, key, onFormulaChange) => {
onFormulaChange({
target: {
name: `penaltyMatrices[${key}].formula`,
value
}
});
};
handleValidateFormula = (value, key) => {
const { errorFormulas } = this.state;
// Reset the errors
errorFormulas[key] = null;
this.setState({ errorFormulas });
return new Promise((resolve, reject) => {
// HIT API
validateFormula(value)
.then(res => {
if (res.code === 'SUCCESS') {
// Check formula validation
resolve(true);
errorFormulas[key] = null;
} else {
reject(false);
errorFormulas[key] = 'Formula tidak valid.';
}
})
.catch(() => {
reject(false);
errorFormulas[key] = 'Something bad happened. Contact developer.';
})
.finally(() => {
this.setState({ errorFormulas });
});
});
};
render() {
const {
formData,
dataAllSupplier,
dataAllAirlines,
dataAllAirports,
dataAllCountries,
dataReasonId,
dataReasonDetail,
penaltyMatricTemplate,
errorFormulas,
reasonLoading
} = this.state;
const isAdd = this.props.match.params.id === undefined;
const _cloneData = cloneDeep(formData);
return (
<Validator
initialValue={_cloneData}
onSubmit={isAdd ? this.handleSubmit : this.handleEdit}
>
{({
values,
errors,
handleChange,
handleSubmit,
handleAddItem,
handleRemoveItem,
setError
}) => {
return (
<Card className="ov--visible">
<form onSubmit={handleSubmit}>
<Head title={`${isAdd ? 'Add' : 'Edit'} Refund Matrix`} />
<div className="row">
<div className="col-xs-4">
<Select
placeholder="Airline Code"
name="airlineCode"
options={dataAllAirlines}
value={get(
values,
`airlineCode.${FORM_DATA_SCHEMA.value}`,
''
)}
onChange={e => {
this.handleFetchReason(e.target.value);
handleChange(e);
}}
error={!isEmpty(errors.airlineCode)}
helperText={errors.airlineCode ? errors.airlineCode : ''}
/>
</div>
<div className="col-xs-4">
<Select
placeholder="Origin"
name="origin"
options={dataAllAirports}
value={get(
values,
`origin.${FORM_DATA_SCHEMA.value}`,
''
)}
onChange={handleChange}
error={!isEmpty(errors.origin)}
helperText={errors.origin ? errors.origin : ''}
/>
</div>
<div className="col-xs-4">
<Select
placeholder="Destination"
name="destination"
options={dataAllAirports}
value={get(
values,
`destination.${FORM_DATA_SCHEMA.value}`,
''
)}
onChange={handleChange}
error={!isEmpty(errors.destination)}
helperText={errors.destination ? errors.destination : ''}
/>
</div>
</div>
<div className="row">
<div className="col-xs-4">
<Select
placeholder="Origin Country"
name="originCountry"
options={dataAllCountries}
value={get(
values,
`originCountry.${FORM_DATA_SCHEMA.value}`,
''
)}
onChange={handleChange}
error={!isEmpty(errors.originCountry)}
helperText={
errors.originCountry ? errors.originCountry : ''
}
/>
</div>
<div className="col-xs-4">
<Select
placeholder="Destination Country"
name="destinationCountry"
options={dataAllCountries}
value={get(
values,
`destinationCountry.${FORM_DATA_SCHEMA.value}`,
''
)}
onChange={handleChange}
error={!isEmpty(errors.destinationCountry)}
helperText={
errors.destinationCountry
? errors.destinationCountry
: ''
}
/>
</div>
<div className="col-xs-4">
<Select
placeholder="Supplier Code"
name="supplierCode"
options={dataAllSupplier}
value={get(
values,
`supplierCode.${FORM_DATA_SCHEMA.value}`,
[]
)}
onChange={handleChange}
error={!isEmpty(errors.supplierCode)}
helperText={
errors.supplierCode ? errors.supplierCode : ''
}
/>
</div>
</div>
<div className="row">
<div className="col-xs-4">
<Select
placeholder="Pax Types"
name="paxTypes"
options={OPTION_PAX_TYPE}
value={get(
values,
`paxTypes.${FORM_DATA_SCHEMA.value}`,
[]
)}
onChange={handleChange}
multi
error={!isEmpty(errors.paxTypes)}
helperText={errors.paxTypes ? errors.paxTypes : ''}
/>
</div>
<div className="col-xs-4">
<Select
placeholder="Cabin Classes"
name="cabinClasses"
options={OPTION_CABIN_CLASS}
value={get(
values,
`cabinClasses.${FORM_DATA_SCHEMA.value}`,
[]
)}
onChange={handleChange}
multi
error={!isEmpty(errors.cabinClasses)}
helperText={
errors.cabinClasses ? errors.cabinClasses : ''
}
/>
</div>
<div className="col-xs-4">
<TixField
error={!isEmpty(errors.description)}
id="description"
name="description"
label="Description"
helperText={errors.description ? errors.description : ''}
margin="normal"
onChange={handleChange}
value={get(
values,
`description.${FORM_DATA_SCHEMA.value}`,
''
)}
variant="outlined"
multiline
row="5"
/>
</div>
</div>
<div className="row">
<div className="col-xs-4">
<InputTag
id="fareClasses"
options={
formData.fareClasses[FORM_DATA_SCHEMA.value].length > 0
? formData.fareClasses[FORM_DATA_SCHEMA.value]
: []
}
onChange={values => {
const target = {
value: values,
name: 'fareClasses'
};
handleChange({ target });
}}
values={
values.fareClasses[FORM_DATA_SCHEMA.value].length > 0
? values.fareClasses[FORM_DATA_SCHEMA.value]
: []
}
label="Fare Classes"
placeholder="Enter multiple Fare Class here"
error={!isEmpty(errors.fareClasses)}
helperText={errors.fareClasses}
info="* Use Tab to separate Fare Classes"
/>
</div>
<div className="col-xs-4">
<InputTag
id="fareBasisCodes"
options={
formData.fareBasisCodes[FORM_DATA_SCHEMA.value].length >
0
? formData.fareBasisCodes[FORM_DATA_SCHEMA.value]
: []
}
onChange={values => {
const target = {
value: values,
name: 'fareBasisCodes'
};
handleChange({ target });
}}
values={
values.fareBasisCodes[FORM_DATA_SCHEMA.value].length > 0
? values.fareBasisCodes[FORM_DATA_SCHEMA.value]
: []
}
label="Fare Basis"
placeholder="Enter multiple Fare Basis Code here"
error={!isEmpty(errors.fareBasisCodes)}
helperText={errors.fareBasisCodes}
info="* Use Tab to separate Fare Basis Code"
/>
</div>
<div className="col-xs-4">
<Select
placeholder="Matrix Type"
name="matrixType"
options={OPTION_REFUND_TYPE}
searchable={false}
value={get(
values,
`matrixType.${FORM_DATA_SCHEMA.value}`,
''
)}
onChange={handleChange}
error={!isEmpty(errors.matrixType)}
helperText={errors.matrixType ? errors.matrixType : ''}
/>
</div>
</div>
<div className="row">
<div className="col-xs-4">
<Select
placeholder="Refund Method"
name="refundMethod"
options={OPTION_REFUND_METHOD}
searchable={false}
value={get(
values,
`refundMethod.${FORM_DATA_SCHEMA.value}`,
''
)}
onChange={handleChange}
error={!isEmpty(errors.refundMethod)}
helperText={
errors.refundMethod ? errors.refundMethod : ''
}
/>
</div>
<div className="col-xs-4">
<Select
placeholder="Reason Id"
name="reasonId"
multi
options={dataReasonId}
value={get(
values,
`reasonId.${FORM_DATA_SCHEMA.value}`,
''
)}
onChange={e => {
const reasonId = e.target.value;
this.handlePopulateReasonDetail(
reasonId,
handleChange,
e
);
}}
error={!isEmpty(errors.reasonId)}
helperText={errors.reasonId ? errors.reasonId : ''}
disabled={dataReasonId.length === 0}
/>
</div>
<div className="col-xs-4">
<div className="ReasonDetailId">
<div
className={[
'Container',
reasonLoading || isEmpty(dataReasonDetail)
? 'disabled'
: ''
].join(' ')}
role="button"
>
<div className="Title">Reason Detail Id</div>
<span className="Toggle Select-arrow" />
{isEmpty(dataReasonId) && (
<div className="EmptyReason">
Please choose <strong>Reason Id</strong> first
</div>
)}
{reasonLoading && (
<div className="EmptyReason">Loading…</div>
)}
{!reasonLoading && !isEmpty(dataReasonDetail) && (
<ul className="Content">
{dataReasonDetail.map((row, idx) => (
<li key={`detail-${idx}`}>
{idx + 1}. {row}
</li>
))}
</ul>
)}
</div>
</div>
</div>
</div>
<div className="row">
<div className="col-xs-6">
<TixDatePicker
clearable
value={this.state.dateOfIssuanceFromTemp}
name="dateOfIssuanceFrom"
label="Date of Issuance From"
onChange={e => {
handleChange(e);
this.handleChangeDate(
e,
setError,
'dateOfIssuanceFrom',
'dateOfIssuanceTo'
);
}}
valueFormat="YYYY-MM-DD"
helperText={errors.dateOfIssuanceFrom}
disablePast={false}
error={!isEmpty(errors.dateOfIssuanceFrom)}
/>
</div>
<div className="col-xs-6">
<TixDatePicker
clearable
value={this.state.dateOfIssuanceToTemp}
name="dateOfIssuanceTo"
label="Date Of Issuance To"
onChange={e => {
handleChange(e);
this.handleChangeDate(
e,
setError,
'dateOfIssuanceFrom',
'dateOfIssuanceTo'
);
}}
valueFormat="YYYY-MM-DD"
helperText={errors.dateOfIssuanceTo}
disablePast={false}
minDate={
this.state.dateOfIssuanceFromTemp
? this.state.dateOfIssuanceFromTemp
: ''
}
hasStartDate
onError={errorMessage => {
setError('dateOfIssuanceTo', errorMessage);
}}
error={!isEmpty(errors.dateOfIssuanceTo)}
/>
</div>
</div>
<div className="row">
<div className="col-xs-6">
<TixDatePicker
clearable
value={this.state.dateOfTravelFromTemp}
name="dateOfTravelFrom"
label="Date of Travel From"
onChange={e => {
handleChange(e);
this.handleChangeDate(
e,
setError,
'dateOfTravelFrom',
'dateOfTravelTo'
);
}}
valueFormat="YYYY-MM-DD"
helperText={errors.dateOfTravelFrom}
disablePast={false}
error={!isEmpty(errors.dateOfTravelFrom)}
/>
</div>
<div className="col-xs-6">
<TixDatePicker
clearable
value={this.state.dateOfTravelToTemp}
name="dateOfTravelTo"
label="Date Of Travel To"
onChange={e => {
handleChange(e);
this.handleChangeDate(
e,
setError,
'dateOfTravelFrom',
'dateOfTravelTo'
);
}}
valueFormat="YYYY-MM-DD"
helperText={errors.dateOfTravelTo}
disablePast={false}
minDate={
this.state.dateOfTravelFromTemp
? this.state.dateOfTravelFromTemp
: ''
}
hasStartDate
onError={errorMessage => {
setError('dateOfTravelTo', errorMessage);
}}
error={!isEmpty(errors.dateOfTravelTo)}
/>
</div>
</div>
<Head title="Penalty Matrices" TagHTML="h3" />
<Wrapper
labelButton={'Matrices'}
onClickAdd={() => {
handleAddItem('penaltyMatrices', penaltyMatricTemplate);
// Add error formulas
this.setState({ errorFormulas: [...errorFormulas, null] });
}}
>
{values.penaltyMatrices.map((list, key) => {
const errorRelationOperator = get(
errors,
`penaltyMatrices[${key}].relationOperator`
);
const errorFormula = get(
errors,
`penaltyMatrices[${key}].formula`
);
const errorCurrency = get(
errors,
`penaltyMatrices[${key}].currency`
);
const errorTimeFrame = get(
errors,
`penaltyMatrices[${key}].timeFrame`
);
const errorMinutes = get(
errors,
`penaltyMatrices[${key}].minutes`
);
return (
<WrapperContent
key={key}
index={key}
dataLength={values.penaltyMatrices.length}
onClickRemove={() => {
handleRemoveItem('penaltyMatrices', key);
// Remove error formulas
const errors = [...errorFormulas];
errors.splice(key, 1);
this.setState({ errorFormulas: errors });
}}
itemType="parent"
isRemoveWrapper
>
<div className="row">
<div className="col-xs-1">
<div className="general-form__item--number">
{key + 1}
</div>
</div>
<div className="col-xs-11">
<div className="row">
<div className="col-xs-4">
<Select
placeholder="Relation Operator"
name={`penaltyMatrices[${key}].relationOperator`}
options={OPTION_RELATION_OPERATORS}
value={get(
list,
`relationOperator.${FORM_DATA_SCHEMA.value}`,
''
)}
onChange={handleChange}
error={!isEmpty(errorRelationOperator)}
searchable={false}
helperText={
errorRelationOperator
? errorRelationOperator
: ''
}
/>
<Select
placeholder="Time Frame"
name={`penaltyMatrices[${key}].timeFrame`}
options={OPTION_TIME_FRAME}
value={get(
list,
`timeFrame.${FORM_DATA_SCHEMA.value}`,
''
)}
onChange={handleChange}
error={!isEmpty(errorTimeFrame)}
helperText={
errorTimeFrame ? errorTimeFrame : ''
}
searchable={false}
/>
<TixField
error={!isEmpty(errorCurrency)}
id="currency"
name={`penaltyMatrices[${key}].currency`}
label="Currency"
helperText={
errorCurrency ? errorCurrency : ''
}
margin="normal"
onChange={handleChange}
value={get(
list,
`currency.${FORM_DATA_SCHEMA.value}`,
''
)}
variant="outlined"
/>
<TixField
type="number"
error={!isEmpty(errorMinutes)}
name={`penaltyMatrices[${key}].minutes`}
id="minutes"
label="Minutes"
helperText={errorMinutes ? errorMinutes : ''}
margin="normal"
onChange={handleChange}
value={get(
list,
`minutes.${FORM_DATA_SCHEMA.value}`,
''
)}
variant="outlined"
/>
</div>
<div className="col-xs-8">
<MatrixCalculator
style={{ marginTop: 16 }}
error={errorFormula}
formulaError={errorFormulas[key]}
selected={get(
list,
`formula.${FORM_DATA_SCHEMA.value}`,
''
)}
onChange={value =>
this.handleFormulaChange(
value,
key,
handleChange
)
}
onSubmit={value =>
this.handleValidateFormula(value, key)
}
/>
</div>
</div>
</div>
</div>
</WrapperContent>
);
})}
</Wrapper>
<Submit title="Submit" onSubmit={handleSubmit} />
</form>
</Card>
);
}}
</Validator>
);
}
}
export const mapStateToProps = () => ({});
const mapDispatchToProps = {
setAlert,
actionSetLoading
};
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Form));
Editor is loading...