Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

381 рядки
17 KiB

  1. // material-ui
  2. import {
  3. Grid,
  4. Typography,
  5. Stack,
  6. Button,
  7. } from '@mui/material';
  8. import * as React from "react";
  9. import * as HttpUtils from "utils/HttpUtils";
  10. import { useNavigate } from "react-router-dom";
  11. import FpsIcon from "assets/images/icons/fps.svg";
  12. import { useLocation } from 'react-router-dom';
  13. import {paymentPath} from "auth/utils";
  14. import {currencyFormat} from "utils/FormatUtils";
  15. // import {poll} from "utils/Utils";
  16. import Loadable from 'components/Loadable';
  17. const LoadingComponent = Loadable(React.lazy(() => import('pages/extra-pages/LoadingComponent')));
  18. import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
  19. import {FormattedMessage} from "react-intl";
  20. const BackgroundHead = {
  21. backgroundImage: `url(${titleBackgroundImg})`,
  22. width: '100%',
  23. height: '100%',
  24. backgroundSize: 'contain',
  25. backgroundRepeat: 'no-repeat',
  26. backgroundColor: '#0C489E',
  27. backgroundPosition: 'right'
  28. }
  29. // ==============================|| DASHBOARD - DEFAULT ||============================== //
  30. const Index = () => {
  31. const navigate = useNavigate()
  32. const location = useLocation();
  33. const [locationData, setLocationData] = React.useState({});
  34. const [paymentData, setPaymentData] = React.useState({});
  35. const [onReady, setOnReady] = React.useState(false);
  36. const [responeData, setResponeDataData] = React.useState({});
  37. const [fpsTransctionData, setFpsTransctionData] = React.useState({});
  38. const [fpsmerchanttimeoutdatetime, setFpsmerchanttimeoutdatetime] = React.useState("");
  39. const [timeDownCount, setTimeDownCount] = React.useState(0);
  40. const [paymentId, setPaymentId] = React.useState("");
  41. const [fpsqrcodeurl, setFpsqrcodeurl] = React.useState("");
  42. const [fpsqrcodeurlPrd, setFpsqrcodeurlPrd] = React.useState("");
  43. const [fpsqrcodeurlFps, setFpsqrcodeurlFps] = React.useState("");
  44. const [browserType, setBrowserType] = React.useState("");
  45. const mobileBrowser = "Mobile";
  46. const desktopBrowser = "Desktop";
  47. const pasgPathPrd = 'https://fps.payapps.hkicl.com.hk'; //PRD
  48. const pasgPath = 'https://sim.fps.payapps.hkicl.com.hk'; //Testing
  49. const loadPaymentUrl = "/api/payment/wallet/fps";
  50. const cancelPaymentUrl = "/api/payment/cancelpayment";
  51. const paymentStatusApi = "/api/payment/status/";
  52. // const payloadUrl = "/api/payment/wallet/fps/enquiryfpspayload/";
  53. // const receiverUrl = "/noti-api/payment/payment-notification";
  54. //timer
  55. const currentTimer = React.useRef();
  56. const [time, setTime] = React.useState(0);
  57. React.useEffect(() => {
  58. // console.log (location.state)
  59. if(Object.keys(location.state).length > 0){
  60. // console.log (location.state)
  61. setLocationData(location.state)
  62. if (/Android|webOS|iPhone|iPad|iPod|Opera Mini/i.test(navigator.userAgent)) {
  63. console.log('Mobile web browser');
  64. setBrowserType(mobileBrowser)
  65. // setFpsqrcodeurl(openPASGUrl)
  66. } else {
  67. console.log('Desktop web browser');
  68. setBrowserType(desktopBrowser)
  69. }
  70. }
  71. }, []);
  72. React.useEffect(() => {
  73. // console.log (locationData)
  74. if (Object.keys(locationData).length > 0){
  75. setPaymentData(locationData)
  76. // loadForm();
  77. }
  78. }, [locationData]);
  79. React.useEffect(() => {
  80. // console.log (paymentData)
  81. if (Object.keys(paymentData).length > 0){
  82. loadForm();
  83. }
  84. }, [paymentData]);
  85. React.useEffect(() => {
  86. // console.log(responeData)
  87. if(Object.keys(responeData).length > 0 && fpsmerchanttimeoutdatetime!=""){
  88. setFpsTransctionData(responeData)
  89. }
  90. }, [responeData]);
  91. React.useEffect(() => {
  92. // console.log(fpsTransctionData)
  93. if(Object.keys(fpsTransctionData).length > 0 ){
  94. setPaymentId(fpsTransctionData.paymentid)
  95. currentTimer.current = setInterval(() => {
  96. setTime((prevTime) => prevTime + 1);
  97. }, 1000);
  98. setOnReady(true);
  99. return () => clearInterval(currentTimer.current);
  100. }
  101. }, [fpsTransctionData]);
  102. const loadForm = () => {
  103. // const timeoutdatetime = "2023-10-26T09:04:30Z[UTC]"
  104. // const convertedDateString = timeoutdatetime.replace("[UTC]", "");
  105. // setFpsmerchanttimeoutdatetime(convertedDateString)
  106. // setPaymentid("C202310268000681")
  107. // setPaymentstatuscode("APPR")
  108. const webtoken = paymentData.webtoken;
  109. const transactionid = paymentData.transactionid;
  110. console.log(webtoken)
  111. console.log(transactionid)
  112. localStorage.removeItem("transactionid")
  113. localStorage.removeItem("webtoken")
  114. localStorage.setItem("transactionid", transactionid)
  115. localStorage.setItem("webtoken", webtoken)
  116. HttpUtils.post({
  117. url: paymentPath+loadPaymentUrl,
  118. params:{
  119. "transactionid": transactionid,
  120. "webtoken": webtoken,
  121. "paymentmethod":"04,BCFP,FPS",
  122. "order": {
  123. "totalamount":paymentData.amount,
  124. "currency":"HKD",
  125. "orderdetail":
  126. [
  127. {
  128. "itemid": "1",
  129. "qty":"1",
  130. "unitprice":paymentData.amount,
  131. "amount":paymentData.amount
  132. },
  133. ]
  134. },
  135. // "locale":"<locale>",
  136. // "eserviceid":"<eserviceid>"
  137. },
  138. onSuccess: function(responseData){
  139. /*
  140. {
  141. "paymentid": "<paymentid>",
  142. "paymentstatus": "<paymentstatus>",
  143. "fpsmerchanttimeoutdatetime": <fpsmerchanttimeoutdatetime>,
  144. "fpsqrcodeimgbase64": "<fpsqrcodeimgbase64>",
  145. "fpsqrcodeurl": "<fpsqrcodeurl>"
  146. }
  147. */
  148. setResponeDataData(responseData)
  149. const timeoutdatetime = responseData.fpsmerchanttimeoutdatetime
  150. const searchString = "[UTC]";
  151. let convertedDateString = "";
  152. if ( timeoutdatetime.toString().includes(searchString) ){
  153. convertedDateString = timeoutdatetime.replace("[UTC]", "");
  154. } else {
  155. convertedDateString = timeoutdatetime;
  156. }
  157. setFpsmerchanttimeoutdatetime(convertedDateString)
  158. const parsedUrl = new URL(responseData.fpsqrcodeurl);
  159. const fpsqrcodeurl = "https://"+window.location.hostname+'/payment'+parsedUrl.pathname;
  160. const fpsqrcodeurlwithFps = "https://"+"fps."+window.location.hostname+parsedUrl.pathname;
  161. console.log(parsedUrl)
  162. console.log(fpsqrcodeurl)
  163. console.log(fpsqrcodeurlwithFps)
  164. const openPASGUrl = pasgPath + '?pay_req_obj=' + encodeURIComponent(fpsqrcodeurl) + '&callback='
  165. + encodeURIComponent("https://"+window.location.hostname+ '/paymentPage/fps/fpscallback?TRANSACTION_ID='+transactionid+"&WEB_TOKEN="+webtoken+"&PAYMENT_ID="+localStorage.getItem("paymentId"));
  166. const openPASGUrlPrd = pasgPathPrd + '?pay_req_obj=' + encodeURIComponent(fpsqrcodeurl) + '&callback='
  167. + encodeURIComponent("https://"+window.location.hostname+ '/paymentPage/fps/fpscallback?TRANSACTION_ID='+transactionid+"&WEB_TOKEN="+webtoken+"&PAYMENT_ID="+localStorage.getItem("paymentId"));
  168. const openPASGUrlPrdFps = pasgPath + '?pay_req_obj=' + encodeURIComponent(fpsqrcodeurlwithFps) + '&callback='
  169. + encodeURIComponent("https://"+window.location.hostname+ '/paymentPage/fps/fpscallback?TRANSACTION_ID='+transactionid+"&WEB_TOKEN="+webtoken+"&PAYMENT_ID="+localStorage.getItem("paymentId"));
  170. setFpsqrcodeurl(openPASGUrl)
  171. setFpsqrcodeurlPrd(openPASGUrlPrd)
  172. setFpsqrcodeurlFps(openPASGUrlPrdFps)
  173. }
  174. });
  175. }
  176. const getPaymentStatus = () => {
  177. if(Object.keys(paymentData).length > 0){
  178. HttpUtils.post({
  179. url: paymentPath+paymentStatusApi+paymentData.transactionid,
  180. params:{
  181. "apprefid": paymentData.transactionid,
  182. "webtoken": paymentData.webtoken,
  183. },
  184. onSuccess: function(responseData){
  185. const paymentstatuscode = responseData.paymentdetail.result.paymentstatuscode;
  186. if (paymentstatuscode != "" && paymentstatuscode != "INPR" ){
  187. if (paymentstatuscode === 'APPR') {
  188. // const timestamp = Date.now();
  189. navigate('/paymentPage/fps/ackpage');
  190. } else if (paymentstatuscode === 'CANC') {
  191. // const timestamp = Date.now();
  192. navigate('/paymentPage/fps/ackpage');
  193. } else {
  194. // window.top.location.href = paymentPath + payment.config.errPagePath;
  195. alert("ERROR")
  196. }
  197. }
  198. },
  199. onError: function(){
  200. cancelPayment()
  201. // clearInterval(currentTimer.current);
  202. }
  203. });
  204. }
  205. };
  206. React.useEffect(() => {
  207. const timeOutDate = new Date(fpsmerchanttimeoutdatetime);
  208. const currentTime = new Date;
  209. const timedowncount = Math.round((timeOutDate.getTime() - currentTime.getTime()) / 1000);
  210. setTimeDownCount(timedowncount);
  211. // console.log(time)
  212. // console.log(timeOutDate)
  213. // console.log(currentTime)
  214. // console.log(timeOutDate.getTime()-currentTime.getTime())
  215. getPaymentStatus();
  216. if (timeOutDate.getTime()<currentTime.getTime()){
  217. console.log("stop");
  218. clearInterval(currentTimer.current);
  219. cancelPayment()
  220. }
  221. },[time])
  222. const cancelPayment = ()=>{
  223. if (Object.keys(paymentData).length>0){
  224. HttpUtils.post({
  225. url: paymentPath+cancelPaymentUrl,
  226. params:{
  227. "transactionid": paymentData.transactionid,
  228. "webtoken": paymentData.webtoken,
  229. "paymentid": fpsTransctionData.paymentid
  230. },
  231. onSuccess: function(){
  232. navigate('/paymentPage/fps/ackpage');
  233. }
  234. });
  235. }
  236. }
  237. const mobliePayment = ()=>{
  238. window.location.assign(fpsqrcodeurl);
  239. }
  240. const mobliePaymentPrd = ()=>{
  241. window.location.assign(fpsqrcodeurlPrd);
  242. }
  243. const mobliePaymentFps = ()=>{
  244. window.location.assign(fpsqrcodeurlFps);
  245. }
  246. return (
  247. !onReady ?
  248. <Grid container sx={{ minHeight: '95vh', mb: 3 }} direction="column" justifyContent="center" alignItems="center">
  249. <Grid item>
  250. <LoadingComponent />
  251. </Grid>
  252. </Grid>
  253. :
  254. (
  255. <Grid container sx={{ minHeight: '110vh', backgroundColor: '#fff' }} direction="column" justifyContent="flex-start" alignItems="center" >
  256. <Grid item xs={12} width="100%">
  257. <div style={BackgroundHead} width="100%">
  258. <Stack direction="row" height='70px'>
  259. <Typography ml={15} color='#FFF' variant="h4" sx={{ pt: 2 }}>
  260. <FormattedMessage id="publicNoticePaymentFPSPay"/>
  261. </Typography>
  262. </Stack>
  263. </div>
  264. </Grid>
  265. {/*row 1*/}
  266. <Grid item xs={12} md={12} >
  267. <Grid container justifyContent="flex-start" alignItems="center" >
  268. <center>
  269. <Grid item xs={12} md={12} >
  270. <Typography variant="h3" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "center" }}>
  271. <img src={FpsIcon} width="80" height="80" alt="FPS"></img>
  272. <br />
  273. <FormattedMessage id="payTotal"/>
  274. <br />
  275. {"HK$ " + currencyFormat(paymentData.amount)}
  276. </Typography>
  277. {browserType==mobileBrowser?
  278. <Typography variant="h3" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "center" }}>
  279. <Button
  280. component="span"
  281. variant="contained"
  282. size="large"
  283. color="primary"
  284. onClick={()=>{
  285. mobliePayment();
  286. }}
  287. sx={{ m: 4 }}
  288. >請選擇支付程式付款-Testing</Button>
  289. <Button
  290. component="span"
  291. variant="contained"
  292. size="large"
  293. color="primary"
  294. onClick={()=>{
  295. mobliePaymentPrd();
  296. }}
  297. sx={{ m: 4 }}
  298. >請選擇支付程式付款-PRD</Button>
  299. <Button
  300. component="span"
  301. variant="contained"
  302. size="large"
  303. color="primary"
  304. onClick={()=>{
  305. mobliePaymentFps();
  306. }}
  307. sx={{ m: 4 }}
  308. >請選擇支付程式付款-fps prefix</Button>
  309. </Typography>
  310. :
  311. <Typography variant="h3" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "center" }}>
  312. 請掃描以下二維碼
  313. <br />
  314. <img src={fpsTransctionData.fpsqrcodeimgbase64} alt="QR Code"/>
  315. <br />
  316. {"["+paymentId+"]"}
  317. <br/>
  318. 二維碼有效期限3分鐘
  319. <br />
  320. 請在規定時間內完成付款流程
  321. <br />
  322. {"剩餘時間: "+timeDownCount+ "秒"}
  323. </Typography>
  324. }
  325. <Typography variant="h3" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "center" }}>
  326. <Button
  327. component="span"
  328. variant="contained"
  329. size="large"
  330. color="error"
  331. onClick={()=>{
  332. cancelPayment();
  333. }}
  334. sx={{ m: 4 }}
  335. >
  336. <FormattedMessage id="payCancel"/>
  337. </Button>
  338. </Typography>
  339. </Grid>
  340. </center>
  341. </Grid>
  342. </Grid>
  343. {/*row 2*/}
  344. </Grid >
  345. )
  346. );
  347. };
  348. export default Index;