Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

MultiPaymentWindow.js 22 KiB

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