From 2af5940b06ba658a403f66442e2265cc5dbbaf8a Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja Date: Mon, 10 Jun 2024 14:14:36 +0530 Subject: [PATCH 1/3] refactor: demo app changes --- Hyperswitch-React-Demo-App/server.js | 212 +++++++++--------- Hyperswitch-React-Demo-App/src/Cart.js | 6 +- .../src/CheckoutForm.js | 70 +++--- Hyperswitch-React-Demo-App/src/Payment.js | 56 +++-- Hyperswitch-React-Demo-App/src/index.css | 4 +- webpack.common.js | 3 +- 6 files changed, 184 insertions(+), 167 deletions(-) diff --git a/Hyperswitch-React-Demo-App/server.js b/Hyperswitch-React-Demo-App/server.js index caddd6e02..73f97d035 100644 --- a/Hyperswitch-React-Demo-App/server.js +++ b/Hyperswitch-React-Demo-App/server.js @@ -1,33 +1,31 @@ const fetch = require("node-fetch"); const express = require("express"); -const app = express(); const { resolve } = require("path"); +const dotenv = require("dotenv"); +const hyper = require("@juspay-tech/hyperswitch-node"); +dotenv.config({ path: "./.env" }); + +const app = express(); +const PORT = 5252; + +const hyperswitch = hyper(process.env.HYPERSWITCH_SECRET_KEY); + +function getUrl(envVar, selfHostedValue) { + return process.env[envVar] === selfHostedValue ? "" : process.env[envVar]; +} + +const SERVER_URL = getUrl("HYPERSWITCH_SERVER_URL", "SELF_HOSTED_SERVER_URL"); +const CLIENT_URL = getUrl("HYPERSWITCH_CLIENT_URL", "SELF_HOSTED_CLIENT_URL"); -// Replace if using a different env file or config -const env = require("dotenv").config({ path: "./.env" }); app.use(express.static("./dist")); app.get("/", (req, res) => { - const path = resolve("./dist" + "/index.html"); + const path = resolve("./dist/index.html"); res.sendFile(path); }); app.get("/completion", (req, res) => { - const path = resolve("./dist" + "/index.html"); + const path = resolve("./dist/index.html"); res.sendFile(path); }); -// replace the test api key with your hyperswitch api key -const hyper = require("@juspay-tech/hyperswitch-node")( - process.env.HYPERSWITCH_SECRET_KEY -); - -const SERVER_URL = - process.env.HYPERSWITCH_SERVER_URL == "SELF_HOSTED_SERVER_URL" - ? "" - : process.env.HYPERSWITCH_SERVER_URL; -const CLIENT_URL = - process.env.HYPERSWITCH_CLIENT_URL == "SELF_HOSTED_CLIENT_URL" - ? "" - : process.env.HYPERSWITCH_CLIENT_URL; - app.get("/config", (req, res) => { res.send({ publishableKey: process.env.HYPERSWITCH_PUBLISHABLE_KEY, @@ -41,108 +39,102 @@ app.get("/urls", (req, res) => { }); }); -app.get("/create-payment-intent", async (req, res) => { - try { - var paymentIntent; - const request = { - currency: "USD", - amount: 2999, - order_details: [ - { - product_name: "Apple iphone 15", - quantity: 1, - amount: 2999, - }, - ], - confirm: false, - capture_method: "automatic", - authentication_type: "three_ds", - customer_id: "hyperswitch_sdk_demo_id", - email: "hyperswitch_sdk_demo_id@gmail.com", - description: "Hello this is description", - // allowed_payment_method_types:["sofort"], - shipping: { - address: { - state: "zsaasdas", - city: "Banglore", - country: "US", - line1: "sdsdfsdf", - line2: "hsgdbhd", - line3: "alsksoe", - zip: "571201", - first_name: "joseph", - last_name: "doe", - }, - phone: { - number: "123456789", - country_code: "+1", - }, +function createPaymentRequest() { + return { + currency: "USD", + amount: 2999, + order_details: [ + { + product_name: "Apple iPhone 15", + quantity: 1, + amount: 2999, + }, + ], + confirm: false, + capture_method: "automatic", + authentication_type: "three_ds", + customer_id: "hyperswitch_sdk_demo_id", + email: "hyperswitch_sdk_demo_id@gmail.com", + description: "Hello this is description", + shipping: { + address: { + line1: "1467", + line2: "Harrison Street", + line3: "Harrison Street", + city: "San Fransico", + state: "California", + zip: "94122", + country: "US", + first_name: "joseph", + last_name: "Doe", }, - connector_metadata: { - noon: { - order_category: "applepay", - }, + phone: { + number: "8056594427", + country_code: "+91", }, - metadata: { - udf1: "value1", - new_customer: "true", - login_date: "2019-09-10T10:11:12Z", + }, + metadata: { + udf1: "value1", + new_customer: "true", + login_date: "2019-09-10T10:11:12Z", + }, + billing: { + address: { + line1: "1467", + line2: "Harrison Street", + line3: "Harrison Street", + city: "San Fransico", + state: "California", + zip: "94122", + country: "US", + first_name: "joseph", + last_name: "Doe", }, - billing: { - address: { - line1: "1467", - line2: "Harrison Street", - line3: "Harrison Street", - city: "San Fransico", - state: "California", - zip: "94122", - country: "US", - first_name: "joseph", - last_name: "Doe", - }, - phone: { - number: "8056594427", - country_code: "+91", - }, + phone: { + number: "8056594427", + country_code: "+91", }, - }; - if (SERVER_URL) { - const apiResponse = await fetch( - `${process.env.HYPERSWITCH_SERVER_URL}/payments`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - Accept: "application/json", - "api-key": process.env.HYPERSWITCH_SECRET_KEY, - }, - body: JSON.stringify(request), - } - ); - paymentIntent = await apiResponse.json(); + }, + }; +} - if (paymentIntent.error) { - return res.status(400).send({ - error: paymentIntent.error, - }); - } - } else { - paymentIntent = await hyper.paymentIntents.create(request); - } +app.get("/create-payment-intent", async (_, res) => { + try { + const paymentRequest = createPaymentRequest(); + const paymentIntent = await createPaymentIntent(paymentRequest); - // Send publishable key and PaymentIntent details to client res.send({ clientSecret: paymentIntent.client_secret, }); } catch (err) { - return res.status(400).send({ - error: { - message: err.message, - }, + res.status(400).send({ + error: { message: err.message }, }); } }); -app.listen(5252, () => - console.log(`Node server listening at http://localhost:5252`) -); +async function createPaymentIntent(request) { + if (SERVER_URL) { + const apiResponse = await fetch(`${SERVER_URL}/payments`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + "api-key": process.env.HYPERSWITCH_SECRET_KEY, + }, + body: JSON.stringify(request), + }); + const paymentIntent = await apiResponse.json(); + + if (paymentIntent.error) { + throw new Error(paymentIntent?.error?.message ?? "Something went wrong."); + } + return paymentIntent; + } else { + return await hyperswitch?.paymentIntents?.create(request); + } +} + +app.listen(PORT, () => { + console.log(`Node server listening at http://localhost:${PORT}`); +}); diff --git a/Hyperswitch-React-Demo-App/src/Cart.js b/Hyperswitch-React-Demo-App/src/Cart.js index 24c19cf58..5e2a7e60f 100644 --- a/Hyperswitch-React-Demo-App/src/Cart.js +++ b/Hyperswitch-React-Demo-App/src/Cart.js @@ -5,14 +5,14 @@ import cap from "../public/assets/cap.png"; function Cart() { return ( <> -
+
-
+
{" "} {" "} Hyperswitch Playground App
-
Test Mode
+
Test Mode
Order Summary(2)
diff --git a/Hyperswitch-React-Demo-App/src/CheckoutForm.js b/Hyperswitch-React-Demo-App/src/CheckoutForm.js index 3a1013d4b..56993eba8 100644 --- a/Hyperswitch-React-Demo-App/src/CheckoutForm.js +++ b/Hyperswitch-React-Demo-App/src/CheckoutForm.js @@ -3,17 +3,15 @@ import Cart from "./Cart"; import { useState, useEffect } from "react"; import { useHyper, useElements } from "@juspay-tech/react-hyper-js"; import { useNavigate } from "react-router-dom"; -import "./App.css"; -import "./index"; import React from "react"; import Completion from "./Completion"; +import "./App.css"; export default function CheckoutForm() { const hyper = useHyper(); const elements = useElements(); const navigate = useNavigate(); - const [isSuccess, setSucces] = useState(false); - + const [isSuccess, setSuccess] = useState(false); const [message, setMessage] = useState(null); const [isProcessing, setIsProcessing] = useState(false); @@ -21,7 +19,7 @@ export default function CheckoutForm() { switch (status) { case "succeeded": setMessage("Payment successful"); - setSucces(true); + setSuccess(true); break; case "processing": setMessage("Your payment is processing."); @@ -55,26 +53,30 @@ export default function CheckoutForm() { setIsProcessing(true); - const { error, status } = await hyper.confirmPayment({ - elements, - confirmParams: { - // Make sure to change this to your payment completion page - return_url: `${window.location.origin}`, - }, - }); + try { + const { error, status } = await hyper.confirmPayment({ + elements, + confirmParams: { + // Make sure to change this to your payment completion page + return_url: `${window.location.origin}`, + }, + }); - if (error) { - setMessage(error.message); - } else { - setMessage("Unexpected Error"); - } + if (error) { + setMessage(error.message); + } else { + setMessage("Unexpected Error"); + } - if (status) { - console.log("-status", status); - handlePaymentStatus(status); + if (status) { + console.log("-status", status); + handlePaymentStatus(status); + } + } catch (error) { + setMessage("Error confirming payment: " + error.message); + } finally { + setIsProcessing(false); } - - setIsProcessing(false); }; useEffect(() => { @@ -107,27 +109,27 @@ export default function CheckoutForm() { }; return ( -
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
http://localhost:9060
-
+
{!isSuccess ? ( <>
-
+
{/* Show any error or success messages */} diff --git a/Hyperswitch-React-Demo-App/src/Payment.js b/Hyperswitch-React-Demo-App/src/Payment.js index 03a28b0db..b7710ec25 100644 --- a/Hyperswitch-React-Demo-App/src/Payment.js +++ b/Hyperswitch-React-Demo-App/src/Payment.js @@ -9,26 +9,41 @@ function Payment() { const [clientSecret, setClientSecret] = useState(""); useEffect(() => { - let url = SELF_SERVER_URL === "" ? ENDPOINT : SELF_SERVER_URL; - Promise.all([ - fetch(`${url}/config`), - fetch(`${url}/urls`), - fetch(`${url}/create-payment-intent`), - ]) - .then((responses) => { - return Promise.all(responses.map((response) => response.json())); - }) - .then((dataArray) => { - const { publishableKey } = dataArray[0]; - const { serverUrl, clientUrl } = dataArray[1]; - const { clientSecret } = dataArray[2]; + const fetchData = async () => { + try { + const url = SELF_SERVER_URL === "" ? ENDPOINT : SELF_SERVER_URL; + + const [configResponse, urlsResponse, paymentIntentResponse] = + await Promise.all([ + fetch(`${url}/config`), + fetch(`${url}/urls`), + fetch(`${url}/create-payment-intent`), + ]); + + if ( + !configResponse.ok || + !urlsResponse.ok || + !paymentIntentResponse.ok + ) { + throw new Error("Network response was not ok"); + } + + const [configData, urlsData, paymentIntentData] = await Promise.all([ + configResponse.json(), + urlsResponse.json(), + paymentIntentResponse.json(), + ]); + + const { publishableKey } = configData; + const { serverUrl, clientUrl } = urlsData; + const { clientSecret } = paymentIntentData; setClientSecret(clientSecret); const script = document.createElement("script"); script.src = `${clientUrl}/HyperLoader.js`; document.head.appendChild(script); script.onload = () => { setHyperPromise( - new Promise((resolve, _) => { + new Promise((resolve) => { resolve( window.Hyper(publishableKey, { customBackendUrl: serverUrl, @@ -45,11 +60,20 @@ function Payment() { }) ); }; - }); + + return () => { + document.head.removeChild(script); + }; + } catch (error) { + console.error("Error fetching data:", error); + } + }; + + fetchData(); }, []); return ( -
+

Hyperswitch Unified Checkout

diff --git a/Hyperswitch-React-Demo-App/src/index.css b/Hyperswitch-React-Demo-App/src/index.css index 4e3c45387..90ff2f352 100644 --- a/Hyperswitch-React-Demo-App/src/index.css +++ b/Hyperswitch-React-Demo-App/src/index.css @@ -21,7 +21,7 @@ main{ font-family:sans-serif ; justify-content: center; } -.mainConatiner{ +.mainContainer{ gap: 1em; padding: 1em; } @@ -294,7 +294,7 @@ margin-left: 10px; .title{ font-size: 20px; } - .mainConatiner{ + .mainContainer{ display: flex; flex-direction: column; justify-content: center; diff --git a/webpack.common.js b/webpack.common.js index 81f350aa7..4335aa6a7 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -6,8 +6,7 @@ const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const CopyPlugin = require("copy-webpack-plugin"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const TerserPlugin = require("terser-webpack-plugin"); -const BundleAnalyzerPlugin = - require("webpack-bundle-analyzer").BundleAnalyzerPlugin; +const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); const { sentryWebpackPlugin } = require("@sentry/webpack-plugin"); const getEnvVariable = (variable, defaultValue) => From 1fb7172ff890c97ce87874a2c5a7daba6f8620d7 Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja Date: Mon, 10 Jun 2024 14:34:04 +0530 Subject: [PATCH 2/3] fix: remove code owner --- .github/CODEOWNERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9924ef8f8..3380f75ae 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -6,9 +6,9 @@ README.md @akash-c-k SECURITY.md @akash-c-k .gitignore @prafulkoppalkar @ArushKapoorJuspay @PritishBudhiraja -Hyperswitch-React-Demo-App/ @prafulkoppalkar @JeevaRamu0104 @PritishBudhiraja -Hyperswitch-React-Demo-App/Dockerfile @JeevaRamu0104 @prafulkoppalkar -Hyperswitch-React-Demo-App/Makefile @JeevaRamu0104 @prafulkoppalkar +Hyperswitch-React-Demo-App/ @prafulkoppalkar @PritishBudhiraja +Hyperswitch-React-Demo-App/Dockerfile @prafulkoppalkar +Hyperswitch-React-Demo-App/Makefile @prafulkoppalkar Hyperswitch-React-Demo-App/promptScript.js @prafulkoppalkar @ArushKapoorJuspay @PritishBudhiraja Hyperswitch-React-Demo-App/webpack.common.js @prafulkoppalkar @ArushKapoorJuspay @PritishBudhiraja Hyperswitch-React-Demo-App/webpack.dev.js @prafulkoppalkar @ArushKapoorJuspay @PritishBudhiraja From 1329d9566b03b630abcc5dd37aedcbe71f24e2d4 Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja Date: Fri, 14 Jun 2024 12:52:00 +0530 Subject: [PATCH 3/3] fix: console added for debug --- Hyperswitch-React-Demo-App/server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Hyperswitch-React-Demo-App/server.js b/Hyperswitch-React-Demo-App/server.js index 9b8d73d15..b19c6f74d 100644 --- a/Hyperswitch-React-Demo-App/server.js +++ b/Hyperswitch-React-Demo-App/server.js @@ -130,6 +130,7 @@ async function createPaymentIntent(request) { const paymentIntent = await apiResponse.json(); if (paymentIntent.error) { + console.error("Error - ", paymentIntent.error); throw new Error(paymentIntent?.error?.message ?? "Something went wrong."); } return paymentIntent;