Search code examples
reactjsnode.jstypescript

Send data from callback on backend to frontend


I have website on React and trying to intergrate the payment engine. The payment engine page is added using iframe, so I can not add onClick event to handle the "Pay" button click when a user pay for the product and then use axios to handle it. For example, when I use axios or fetch in my frontend, it fires before the user submits the payment form.

Instead, the payment engine sends a post request to a serviceUrl which I provided whenever a user submits their form.

So, I got the post request from them:

app.post("/api/payment-status", (req, res) => {
  console.log("Payment status received");
  const {transactionStatus, reason, reasonCode} = JSON.parse(Object.keys(req.body)[0]);
  console.log("transactionStatus: ", transactionStatus, "reason: ", reason, "reasonCode: ", reasonCode);
  let paymentData = {};

  if (transactionStatus === webConfig.wfpTransactionStatus && reason === webConfig.wfpReason && reasonCode === Number(webConfig.wfpReasonCode)) {
      console.log("Success!!!");
      paymentData = {
        isSuccess: true,
        wfpStatus: transactionStatus,
        wfpReason: reason,
        msg: "Success.",
        wfpReasonCode: reasonCode
      };
  } else {
      console.log("Failed!!!!");
      paymentData = {
        isSuccess: false,
        wfpStatus: transactionStatus,
        wfpReason: reason,
        msg: `Failed: ${reasonCode}!`,
        wfpReasonCode: reasonCode
      };
  }

  res.status(200).send("Payment status received.");
});

I must send paymentData object to frontend.

So, I deciced to use the socket.io to transfer data from backend to a client.

Backend code:

const socketIO = require("socket.io");

const io = socketIO(server, {
  cors: {
    origin: "https://www.my-domain.com",
    methods: ["GET", "POST"]
  }
});

io.on("connection", (socket) => {
  console.log("A client connected: ", socket.id);

  socket.on("paymentClientID", (offerID) => {
    console.log("Client ID on backend: ", offerID);
  });

  socket.on("disconnect", () => {
    console.log("A client disconnected: ", socket.id);
    socket.close();
    socket.disconnect();
  });
});

app.post("/api/payment-status", (req, res) => {
  console.log("Payment status received");
  const {transactionStatus, reason, reasonCode, orderReference} = JSON.parse(Object.keys(req.body)[0]);
  console.log("transactionStatus: ", transactionStatus, "reason: ", reason, "reasonCode: ", reasonCode, "orderReference: ", orderReference);
  let paymentData = {};

  if (transactionStatus === webConfig.wfpTransactionStatus && reason === webConfig.wfpReason && reasonCode === Number(webConfig.wfpReasonCode) && orderReference) {
      console.log("Success!!!");
      paymentData = {
        isSuccess: true,
        wfpOrderReference: orderReference,
        wfpStatus: transactionStatus,
        wfpReason: reason,
        msg: "Success.",
        wfpReasonCode: reasonCode
      };
  } else {
      console.log("Failed!!!!");
      paymentData = {
        isSuccess: false,
        wfpOrderReference: orderReference,
        wfpStatus: transactionStatus,
        wfpReason: reason,
        msg: `Failed: ${reasonCode}!`,
        wfpReasonCode: reasonCode
      };
  }

  io.emit("paymentStatus", paymentData);
  res.status(200).send("Статус платежу отримано");
});

Frontend code:

import io from "socket.io-client";
const socket = io("https://www.my-domain.com");

useEffect(() => {
    const wfpPaymentStatusSocket = () => {
      socket.emit("paymentClientID", offerID);

      socket.on("paymentStatus", (data) => {
        console.log("Data: ", data);
        alert(data);
        socket.emit("disconnect");
        console.log("Disconnecting....");
      });
    };

    wfpPaymentStatusSocket();
  }, [socket]);

From server logs, I see only:

A client connected: NUDCr7GnZclJuNYBAAAi

Client ID on backend: 16132880

A client connected: ex9Kg5g-Bejn6oncAAAk

Client ID on backend: 16132880

For some reason it does not receive the following data:

socket.on("paymentStatus", (data) => {
  console.log("Data: ", data);
  alert(data);
  socket.emit("disconnect");
  console.log("Disconnecting....");
});

Any ideas why it does not receive paymentStatus data on a client (frontend)?


Solution

  • So, I fixed this issue by adding:

    app.emit("paymentStatusReceived", paymentData);

    app.post("/api/payment-status", (req, res) => {
      console.log("Payment status received");
      const {transactionStatus, reason, reasonCode, orderReference} = JSON.parse(Object.keys(req.body)[0]);
      console.log("transactionStatus: ", transactionStatus, "reason: ", reason, "reasonCode: ", reasonCode, "orderReference: ", orderReference);
      let paymentData = {};
    
      if (transactionStatus === webConfig.wfpTransactionStatus && reason === webConfig.wfpReason && reasonCode === Number(webConfig.wfpReasonCode) && orderReference) {
          console.log("Success!!!");
          paymentData = {
            isSuccess: true,
            wfpOrderReference: orderReference,
            wfpStatus: transactionStatus,
            wfpReason: reason,
            msg: "Success.",
            wfpReasonCode: reasonCode
          };
      } else {
          console.log("Failed!!!!");
          paymentData = {
            isSuccess: false,
            wfpOrderReference: orderReference,
            wfpStatus: transactionStatus,
            wfpReason: reason,
            msg: `Failed: ${reasonCode}!`,
            wfpReasonCode: reasonCode
          };
      }
    
      app.emit("paymentStatusReceived", paymentData);
      res.status(200).send("Статус платежу отримано");
    });
    

    This will trigger the event to indicate that payment status is received.

    Then I created the route to handle the Axios request from the frontend using GET method.

    app.get("/api/get-payment-data", (req, res) => {
        // Listen for the paymentStatusReceived event
        app.once("paymentStatusReceived", (paymentData) => {
            // Send the payment data to the frontend
            res.json(paymentData);
        });
    });
    

    Now, it displays the "pending" status for the Axios GET request from React and waits until the callback is received from the payment engine. After I get the callback it sends the paymentData to the frontend (React). The issue is resolved.