25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

473 lines
21 KiB

  1. import {
  2. useEffect,
  3. useState
  4. } from "react";
  5. import * as React from "react";
  6. import {getBowserType} from "auth/utils";
  7. // material-ui
  8. import {
  9. Button,
  10. FormLabel,
  11. Stack,
  12. Typography,
  13. Dialog,
  14. DialogActions,
  15. DialogContent,
  16. DialogContentText,
  17. DialogTitle,
  18. Grid,
  19. Box
  20. } from '@mui/material';
  21. import { useFormik, FormikProvider } from 'formik';
  22. import * as yup from 'yup';
  23. import Loadable from 'components/Loadable';
  24. const LoadingComponent = Loadable(React.lazy(() => import('pages/extra-pages/LoadingComponent')));
  25. import * as FormatUtils from "utils/FormatUtils";
  26. import VisaIcon from "assets/images/icons/visacard.svg";
  27. import MasterIcon from "assets/images/icons/mastercard.svg";
  28. import JcbIcon from "assets/images/icons/jcb.svg";
  29. import UnionPayIcon from "assets/images/icons/unionpay.svg";
  30. import PpsIcon from "assets/images/icons/ppshk.svg";
  31. import FpsIcon from "assets/images/icons/fps.svg";
  32. import {FormattedMessage, useIntl} from "react-intl";
  33. import * as HttpUtils from "utils/HttpUtils"
  34. import * as UrlUtils from "utils/ApiPathConst"
  35. const MultiPaymentWindow = (props) => {
  36. const intl = useIntl();
  37. const windowTitle = intl.formatMessage({id: 'selectPaymentMethod'});
  38. // const [content, setContent] = useState();
  39. const [loadtTransactionData, setLoadtTransactionData] = useState({});
  40. const [loadAvailableMethodData, setLoadAvailableMethodData] = useState([]);
  41. const [paymentMethod, setPaymentMethod] = useState("");
  42. const [isLimit, setIsLimit] = useState(false);
  43. const [isPPSLimit, setIsPPSLimit] = useState(false);
  44. const [transactionData, setTransactionData] = useState({});
  45. const [availableMethodData, setAvailableMethodData] = useState([]);
  46. const [fpsClass, setFpsClass] = useState("");
  47. const [visaClass, setVisaClass] = useState("");
  48. const [mastercardClass, setMastercardClass] = useState("");
  49. const [jCBClass, setJCBClass] = useState("");
  50. const [unionPayClass, setUnionPayClass] = useState("");
  51. const [pPSClass, setPPSlass] = useState("");
  52. const [filteredPaymentMethod, setFilteredPaymentMethod] = useState([]);
  53. const [onReady, setOnReady] = useState(false);
  54. const [paymentHoldedErrText, setPaymentHoldedErrText] = React.useState("");
  55. const [paymentHoldedErr, setPaymentHoldedErr] = React.useState(false);
  56. useEffect(() => {
  57. // console.log(props.transactionData)
  58. if(Object.keys(props.transactionData).length > 0){
  59. setLoadtTransactionData(props.transactionData)
  60. }
  61. }, [props.transactionData]);
  62. useEffect(() => {
  63. // console.log(props.availableMethods)
  64. if(props.availableMethods.length > 0){
  65. setLoadAvailableMethodData(props.availableMethods)
  66. }
  67. }, [props.availableMethods]);
  68. useEffect(() => {
  69. if(Object.keys(loadtTransactionData).length > 0){
  70. setTransactionData(loadtTransactionData)
  71. }
  72. }, [loadtTransactionData]);
  73. useEffect(() => {
  74. if(Object.keys(transactionData).length > 0&&props.availableMethods.length > 0){
  75. setLoadAvailableMethodData(props.availableMethods)
  76. }
  77. }, [transactionData]);
  78. useEffect(() => {
  79. if(loadAvailableMethodData.length > 0){
  80. setAvailableMethodData(loadAvailableMethodData)
  81. }
  82. }, [loadAvailableMethodData]);
  83. useEffect(() => {
  84. if(filteredPaymentMethod!= undefined && filteredPaymentMethod.length>0){
  85. setOnReady(true)
  86. } else if(filteredPaymentMethod!= undefined && Object.keys(filteredPaymentMethod).length > 0){
  87. setOnReady(true)
  88. }
  89. }, [filteredPaymentMethod]);
  90. useEffect(() => {
  91. const availableMethod = availableMethodData;
  92. if(props.availableMethods.length > 0){
  93. const filteringPaymentMethod = availableMethod.filter(obj => {
  94. if (obj.supportedcard && obj.supportedcard.includes(paymentMethod)) {
  95. return obj.subtype === "CreditCard";
  96. }
  97. return obj.subtype === paymentMethod;
  98. });
  99. if (isLimit && filteringPaymentMethod!= undefined && filteringPaymentMethod.length>0){
  100. if (paymentMethod == "FPS" || paymentMethod == "PPS"){
  101. filteringPaymentMethod[0].pointstonote = paymentMethod + intl.formatMessage({id: 'paymentLimitPrice1'})
  102. setFilteredPaymentMethod(filteringPaymentMethod[0]);
  103. } else if (isLimit) {
  104. filteringPaymentMethod[0].pointstonote = paymentMethod + intl.formatMessage({id: 'paymentLimitPrice2'})
  105. setFilteredPaymentMethod(filteringPaymentMethod[0]);
  106. }
  107. }
  108. if (!isLimit && filteringPaymentMethod!= undefined && filteringPaymentMethod.length>0){
  109. setFilteredPaymentMethod(filteringPaymentMethod);
  110. }
  111. if(isPPSLimit && filteringPaymentMethod!= undefined && filteringPaymentMethod.length>0 && paymentMethod =="PPS"){
  112. filteringPaymentMethod[0].pointstonote = paymentMethod + intl.formatMessage({id: 'paymentLimitPPS'})
  113. setFilteredPaymentMethod(filteringPaymentMethod[0]);
  114. }
  115. setFpsClass(paymentMethod == "FPS" || paymentMethod == "" ? "" : "grayscale")
  116. setVisaClass(paymentMethod == "Visa" || paymentMethod == "" ? "" : "grayscale")
  117. setMastercardClass(paymentMethod == "MasterCard" || paymentMethod == "" ? "" : "grayscale")
  118. setJCBClass(paymentMethod == "JCB" || paymentMethod == "" ? "" : "grayscale")
  119. setUnionPayClass(paymentMethod == "UnionPay" || paymentMethod == "" ? "" : "grayscale")
  120. setPPSlass(paymentMethod == "PPS" || paymentMethod == "" ? "" : "grayscale")
  121. }
  122. }, [paymentMethod]);
  123. const selectedPaymentMethodHandle = (method) => () =>{
  124. if (method != paymentMethod){
  125. resetForm()
  126. let totalAmount = props.totalAmount;
  127. // totalAmount = 99999999.99
  128. // totalAmount = 0.01
  129. const paymentLimitList = props.paymentLimit
  130. let limitRecordList;
  131. switch (method) {
  132. case "Visa":
  133. case "JCB":
  134. case "MasterCard":
  135. limitRecordList = paymentLimitList.creditCardLimitRecord;
  136. break;
  137. case "FPS":
  138. limitRecordList = paymentLimitList.fpsLimitRecord;
  139. break;
  140. case "PPS":
  141. limitRecordList = paymentLimitList.ppsbLimitRecord;
  142. break;
  143. case "UnionPay":
  144. limitRecordList = paymentLimitList.unionPlayLimitRecord;
  145. break;
  146. default:
  147. break;
  148. }
  149. if (totalAmount >= limitRecordList.minLimit && totalAmount <= limitRecordList.maxLimit) {
  150. setIsLimit(false)
  151. } else {
  152. setIsLimit(true)
  153. }
  154. if (getBowserType() === "PC_Browser"){
  155. setPaymentMethod(method)
  156. props.setSelectedPaymentMethod(method);
  157. setIsPPSLimit(false)
  158. } else if (getBowserType() !== "PC_Browser" && method !== "PPS"){
  159. setPaymentMethod(method)
  160. props.setSelectedPaymentMethod(method);
  161. } else {
  162. setPaymentMethod(method)
  163. setIsPPSLimit(true)
  164. }
  165. }
  166. };
  167. const confirmPaymentHandle = () => () =>{
  168. handlePaymentCheck()
  169. };
  170. const handlePaymentCheck = () => {
  171. let appIdList = props.appIds
  172. // console.log(props.appIds)
  173. // console.log(appIdList)
  174. HttpUtils.post({
  175. url: UrlUtils.PAYMENT_CHECK,
  176. params: {
  177. appIds: appIdList
  178. },
  179. onSuccess: (responseData) => {
  180. const latestData = {};
  181. responseData.forEach(item => {
  182. const { appId, timeDiff } = item;
  183. if (latestData[appId] === undefined || timeDiff < latestData[appId].timeDiff) {
  184. latestData[appId] = item;
  185. }
  186. });
  187. const latestDataObjects = Object.values(latestData);
  188. const filteredData = latestDataObjects.filter(item => item.timeDiff > 20 && item.status !== "APPR");
  189. const filteredAppIds = filteredData.map(item => item.appId);
  190. const appIdsNotInData = appIdList.filter(appId => !latestDataObjects.some(item => item.appId === appId));
  191. const combinedAppIdsArray = [...appIdsNotInData, ...filteredAppIds];
  192. const readyToPayment = appIdList.every(appId => combinedAppIdsArray.includes(appId));
  193. if (readyToPayment){
  194. // props.setConfirmPayment(true);
  195. return;
  196. }else{
  197. const appIdsInData = appIdList.filter(appId => !combinedAppIdsArray.some(item => item === appId));
  198. const HoldingApplication = latestDataObjects.filter(item => appIdsInData.includes(item.appId));
  199. const resultString = HoldingApplication.map(item => item.appNo).join(' , ');
  200. setPaymentHoldedErrText(resultString);
  201. // setPaymentHoldedErrText(intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: record.appNo }));
  202. setPaymentHoldedErr(true);
  203. }
  204. }
  205. });
  206. };
  207. const closeHandle = () => () =>{
  208. resetForm()
  209. props.setOpen(false)
  210. };
  211. const resetForm = () =>{
  212. setOnReady(false)
  213. setPaymentMethod("")
  214. setFilteredPaymentMethod([])
  215. setIsLimit(false)
  216. setIsPPSLimit(false)
  217. };
  218. useEffect(() => {
  219. if(props.selectedPaymentMethod === ""){
  220. setPaymentMethod("")
  221. }
  222. }, [availableMethodData]);
  223. const formik = useFormik({
  224. initialValues: ({
  225. username: '',
  226. }),
  227. validationSchema: yup.object().shape({
  228. }),
  229. });
  230. return (
  231. <Dialog
  232. open={props.open}
  233. onClose={() => props.setOpen(false)}
  234. fullWidth={true}
  235. maxWidth={'xl'}
  236. fullScreen={props.isFullScreen}
  237. >
  238. <DialogTitle >
  239. <Grid container>
  240. <Grid item>
  241. <Stack direction="row" justifyContent="flex-start" alignItems="center">
  242. <Typography variant="h4">
  243. {windowTitle}
  244. </Typography>
  245. </Stack>
  246. </Grid>
  247. </Grid>
  248. </DialogTitle>
  249. <FormikProvider value={formik}>
  250. <form>
  251. <DialogContent>
  252. <DialogContentText>
  253. <Grid item xs={12} md={12} sx={{ pt: 2 }} style={{ height: '100%' }} width="100%">
  254. <Box xs={12} md={12} sx={{ p: 4, border: '3px solid #eee', borderRadius: '10px' }} >
  255. <Grid container justifyContent="flex-start" alignItems="left" >
  256. <center>
  257. <Grid item xs={12} md={12} width="100%">
  258. <Typography variant="h5" sx={{ textAlign: "left" }}>
  259. <FormattedMessage id="transactionRefNo"/>: {transactionData.transactionid}
  260. </Typography>
  261. {/* <Typography variant="h5" sx={{ textAlign: "left" }}>
  262. 支付金額: HK$ {FormatUtils.currencyFormat(props.totalAmount)}
  263. </Typography> */}
  264. {!props.onReady ?
  265. <LoadingComponent />
  266. :availableMethodData.length>0?
  267. <Grid container spacing={2} direction="column" justifyContent="space-between" alignItems="flex-start">
  268. <Grid item xs={12} md={12}>
  269. <Grid container spacing={1} direction="row" justifyContent="flex-start" alignItems="center">
  270. <Grid item>
  271. <Typography variant="h5" sx={{ textAlign: "left" }}>
  272. <FormattedMessage id="selectPaymentMethod"/>:
  273. </Typography>
  274. </Grid>
  275. <Grid item sx={{display: { sm: 'block', md: 'none' }}}></Grid>
  276. <Grid item>
  277. <Button variant="contained" color="white" onClick={selectedPaymentMethodHandle("FPS")} disabled={props.fpsStatus.active === "N"}>
  278. <img className={fpsClass} src={FpsIcon} width="80" height="80" alt="FPS"></img>
  279. </Button>
  280. </Grid>
  281. <Grid item>
  282. <Button variant="contained" color="white" onClick={selectedPaymentMethodHandle("Visa")} disabled={props.creditCardStatus.active === "N"}>
  283. <img className={visaClass} src={VisaIcon} width="80" height="80" alt="Visa"></img>
  284. </Button>
  285. </Grid>
  286. <Grid item>
  287. <Button variant="contained" color="white" onClick={selectedPaymentMethodHandle("MasterCard")} disabled={props.creditCardStatus.active === "N"}>
  288. <img className={mastercardClass} src={MasterIcon} width="80" height="80" alt="MasterCard"></img>
  289. </Button>
  290. </Grid>
  291. <Grid item>
  292. <Button variant="contained" color="white" onClick={selectedPaymentMethodHandle("UnionPay")} disabled={props.unionPayStatus.active === "N"}>
  293. <img className={unionPayClass} src={UnionPayIcon} width="80" height="80" alt="UnionPay"></img>
  294. </Button>
  295. </Grid>
  296. <Grid item>
  297. <Button variant="contained" color="white" onClick={selectedPaymentMethodHandle("JCB")} disabled={props.unionPayStatus.active === "N"}>
  298. <img className={jCBClass} src={JcbIcon} width="80" height="80" alt="JCB"></img>
  299. </Button>
  300. </Grid>
  301. <Grid item>
  302. <Button variant="contained" color="white" onClick={selectedPaymentMethodHandle("PPS")} disabled={props.ppsStatus.active === "N"}>
  303. <img className={pPSClass} src={PpsIcon} width="80" height="80" alt="PPS"></img>
  304. </Button>
  305. </Grid>
  306. </Grid>
  307. </Grid>
  308. {paymentMethod !=""?
  309. <Grid item xs={12} md={12}>
  310. <Grid container direction="row" justifyContent="flex-start" alignItems="center">
  311. <Grid item>
  312. <FormLabel sx={{ fontSize: "20px", color: "#000000", textAlign: "center" }}>
  313. <FormattedMessage id="selectedPaymentMethod"/>:&nbsp;
  314. </FormLabel>
  315. </Grid>
  316. <Grid item>
  317. <FormLabel sx={{ fontSize: "20px", color: "#000000", textAlign: "center" }}>
  318. {paymentMethod}
  319. </FormLabel>
  320. </Grid>
  321. </Grid>
  322. </Grid>
  323. : null}
  324. </Grid>:
  325. <Grid container direction="row" justifyContent="center" alignItems="center">
  326. <FormLabel sx={{ fontSize: "20px", color: "#000000", textAlign: "center"}}>
  327. <FormattedMessage id="paymentMethodNotAvailable"/>。
  328. </FormLabel>
  329. </Grid>
  330. }
  331. </Grid>
  332. <Grid item xs={12} md={12}>
  333. <Grid container >
  334. <Grid item>
  335. <Typography variant="pnspsFormParagraphBold" sx={{ color: "#000000", textAlign: "left" }}>
  336. <FormattedMessage id="payTotal"/>(HK$):&nbsp;
  337. </Typography>
  338. </Grid>
  339. <Grid item>
  340. <Typography variant="pnspsFormParagraphBold" sx={{color: "#000000", textAlign: "left" }}>
  341. {" HK$ " + FormatUtils.currencyFormat(props.totalAmount)}
  342. </Typography>
  343. </Grid>
  344. </Grid>
  345. {paymentMethod === "" ?
  346. paymentMethod !="" && !onReady ? <LoadingComponent/> : null
  347. :
  348. !isLimit?
  349. !onReady? <LoadingComponent/> :
  350. !isLimit?
  351. filteredPaymentMethod.map((availableMethod) => {
  352. return (
  353. <Grid container key={availableMethod.subtype} className={"css-1tx0bae"} sx={{ mt: 1, p:2 }}>
  354. {
  355. availableMethod.pointstonote.map((pointstonote) => {
  356. return (
  357. <Grid container key={pointstonote.order} sx={{ p:0.5 }} direction="row" justifyContent="flex-start" alignItems="center">
  358. <Grid item>
  359. <Typography sx={{fontSize: "16px", color: "#000000", textAlign: "left" }}>
  360. {pointstonote.content}
  361. </Typography>
  362. </Grid>
  363. </Grid>
  364. );
  365. })
  366. }
  367. </Grid>
  368. );
  369. })
  370. : null
  371. :
  372. !onReady? <LoadingComponent/> :
  373. <Grid container className={"css-1tx0bae"} sx={{ mt: 1, p:2 }}>
  374. <Grid container sx={{ p:0.5 }} direction="row" justifyContent="flex-start" alignItems="center">
  375. <Grid item>
  376. <Typography color="error" sx={{fontSize: "16px", textAlign: "left" }}>
  377. {filteredPaymentMethod.pointstonote}
  378. </Typography>
  379. </Grid>
  380. </Grid>
  381. </Grid>
  382. }
  383. </Grid>
  384. </center>
  385. </Grid>
  386. </Box>
  387. </Grid>
  388. </DialogContentText>
  389. </DialogContent>
  390. </form>
  391. </FormikProvider>
  392. <Stack direction="row" justifyContent="space-around">
  393. <DialogActions>
  394. <Button variant="contained" onClick={closeHandle()} autoFocus >
  395. <FormattedMessage id="cancel"/>
  396. </Button>
  397. </DialogActions>
  398. <DialogActions>
  399. <Button variant="contained" color="success" onClick={confirmPaymentHandle()} disabled={paymentMethod === "" || isLimit || isPPSLimit}>
  400. <FormattedMessage id="pay"/>
  401. </Button>
  402. </DialogActions>
  403. </Stack>
  404. <div>
  405. <Dialog
  406. open={paymentHoldedErr}
  407. onClose={() => setPaymentHoldedErr(false)}
  408. PaperProps={{
  409. sx: {
  410. minWidth: '40vw',
  411. maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '70vw' },
  412. maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '60vh' }
  413. }
  414. }}
  415. >
  416. <DialogTitle></DialogTitle>
  417. <Typography variant="h4" style={{ paddingLeft: '24px' }}><FormattedMessage id="MSG.actionFail" /></Typography>
  418. <DialogContent style={{ display: 'flex', }}>
  419. <Stack direction="column" justifyContent="space-between">
  420. <div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: paymentHoldedErrText }) }} />
  421. </Stack>
  422. </DialogContent>
  423. <DialogActions>
  424. <Button onClick={() => setPaymentHoldedErr(false)} aria-label={intl.formatMessage({ id: 'close' })}>
  425. <Typography variant="h5">
  426. <FormattedMessage id="close" />
  427. </Typography></Button>
  428. </DialogActions>
  429. </Dialog>
  430. </div>
  431. </Dialog>
  432. );
  433. };
  434. export default MultiPaymentWindow;