@a-tech.jo/atech_payment 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.babelrc ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "plugins": ["@babel/syntax-dynamic-import"],
3
+ "presets": ["@babel/preset-env", "@babel/preset-react"]
4
+ }
package/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # my-webpack-project
2
+
3
+ A React component that integrates PayPal payments into your application.
4
+
5
+ ## Steps for Usage
6
+
7
+ 1. **Build the Package**
8
+ Run `npm run build` in your package directory to build the project.
9
+
10
+ 2. **Local Testing**
11
+ To test the package locally:
12
+
13
+ - First, link the package by running `npm link` in the package directory.
14
+ - Then, in the app where you want to use the package, link it using `npm link my-webpack-project`.
15
+ - Last, make sure `atech_payment_backend` is running at port 5000.
16
+
17
+ 3. **Publishing**
18
+ When ready to share the package, publish it by running `npm publish`.
19
+ After publishing, it can be installed in any app using:
20
+ `npm install my-webpack-project`
@@ -0,0 +1,18 @@
1
+
2
+ Test cards:
3
+ https://wordpresshyperpay.docs.oppwa.com/reference/parameters#test-accounts
4
+
5
+
6
+
7
+ Purchase a product:
8
+ References:
9
+ https://wordpresshyperpay.docs.oppwa.com/integrations/widget
10
+
11
+
12
+
13
+
14
+
15
+ Subscribe:
16
+ References:
17
+
18
+
File without changes
package/index.html ADDED
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Webpack App</title>
6
+ </head>
7
+ <body>
8
+ <h1>Hello world!</h1>
9
+ <h2>Tip: Check your console</h2>
10
+ </body>
11
+
12
+ </html>
package/index.js ADDED
@@ -0,0 +1,36 @@
1
+ import HyperpayOrder from "./src/hyperpay/hyperpayOrder.js";
2
+ import PaypalOrder from "./src/paypal/paypalOrder.js";
3
+
4
+ const PymentOrder = ({
5
+ provider = "hyperpay",
6
+ order = {},
7
+ clientId = "test",
8
+ onChange = () => {},
9
+ onStatusChange = () => {},
10
+ env = "development",
11
+ redirectUrl = "",
12
+ }) => {
13
+ if (provider === "paypal") {
14
+ console.log(process.env.API_URL);
15
+ return (
16
+ <PaypalOrder
17
+ order={order}
18
+ clientId={clientId}
19
+ onChange={onChange}
20
+ onStatusChange={onStatusChange}
21
+ env={env}
22
+ />
23
+ );
24
+ }
25
+
26
+ if (provider === "hyperpay") {
27
+ console.log(process.env.API_URL);
28
+ return (
29
+ <HyperpayOrder order={order} redirectUrl={redirectUrl} env={env} />
30
+ );
31
+ }
32
+
33
+ return <div />;
34
+ };
35
+
36
+ export { PymentOrder };
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@a-tech.jo/atech_payment",
3
+ "version": "1.0.1",
4
+ "type": "module",
5
+ "description": "A-Tech Payment React Package",
6
+ "source": "index.js",
7
+ "main": "dist/index.js",
8
+ "module": "dist/index.module.js",
9
+ "unpkg": "dist/index.umd.js",
10
+ "publishConfig": {
11
+ "access": "restricted"
12
+ },
13
+ "scripts": {
14
+ "build": "webpack --mode=production --node-env=production",
15
+ "dev": "microbundle watch",
16
+ "test": "echo \"Error: no test specified\" && exit 1",
17
+ "main": "lib/index.js",
18
+ "build:dev": "webpack --mode=development",
19
+ "build:prod": "webpack --mode=production --node-env=production",
20
+ "watch": "webpack --watch",
21
+ "serve": "webpack serve"
22
+ },
23
+ "author": "A-Tech",
24
+ "license": "ISC",
25
+ "peerDependencies": {
26
+ "react": ">=15.0.1",
27
+ "react-dom": ">=15.0.1"
28
+ },
29
+ "devDependencies": {
30
+ "@babel/core": "^7.25.2",
31
+ "@babel/preset-env": "^7.24.3",
32
+ "@babel/preset-react": "^7.24.7",
33
+ "@webpack-cli/generators": "^3.0.7",
34
+ "babel-loader": "^9.1.3",
35
+ "dotenv-webpack": "^8.1.0",
36
+ "html-webpack-plugin": "^5.6.0",
37
+ "prettier": "^2.8.4",
38
+ "react": ">=15.0.1",
39
+ "react-dom": ">=15.0.1",
40
+ "webpack": "^5.91.0",
41
+ "webpack-cli": "^5.1.4",
42
+ "webpack-dev-server": "^5.0.4"
43
+ },
44
+ "dependencies": {
45
+ "@paypal/react-paypal-js": "^8.7.0",
46
+ "axios": "^1.7.7",
47
+ "dotenv": "^16.4.5"
48
+ },
49
+ "directories": {
50
+ "example": "example"
51
+ }
52
+ }
@@ -0,0 +1,99 @@
1
+ import { useEffect, useState } from "react";
2
+ import hyperpayConnector from "../shared/requests/hyperpayConnector.js";
3
+
4
+ const HyperpayOrder = ({ redirectUrl, order, env }) => {
5
+ const [error, setError] = useState(null);
6
+ const [checkoutId, setCheckoutId] = useState(null);
7
+ const [isLoading, setIsLoading] = useState(false);
8
+
9
+ useEffect(() => {
10
+ if (order) {
11
+ initiateOrder();
12
+ }
13
+ }, [order]);
14
+
15
+ const initiateOrder = async () => {
16
+ try {
17
+ if (!order) {
18
+ setError("Data must be provided");
19
+ return;
20
+ }
21
+ setIsLoading(true);
22
+ const result = await hyperpayConnector.createHyperpayOrder(order, env);
23
+ setIsLoading(false);
24
+
25
+ if (result?.error) {
26
+ setError(result.error);
27
+ return;
28
+ }
29
+
30
+ setCheckoutId(result?.id);
31
+ } catch (err) {
32
+ console.error("err", err);
33
+ setError("An unexpected error occurred.");
34
+ }
35
+ };
36
+
37
+ const checkout = async ( ) => {
38
+ try {
39
+ if (!checkoutId) {
40
+ setError("Checkout ID must be provided");
41
+ return;
42
+ }
43
+ setIsLoading(true);
44
+ const result = await hyperpayConnector.getOrderStatus(checkoutId, env);
45
+ setIsLoading(false);
46
+
47
+ if (result?.error) {
48
+ setError(result.error);
49
+ return;
50
+ }
51
+
52
+ return result;
53
+ } catch (err) {
54
+ console.error("err", err);
55
+ setError("An unexpected error occurred.");
56
+ }
57
+ }
58
+
59
+ useEffect(() => {
60
+ if (checkoutId) {
61
+ const script = document.createElement("script");
62
+ script.src = `https://eu-test.oppwa.com/v1/paymentWidgets.js?checkoutId=${checkoutId}`;
63
+ script.async = true;
64
+ script.crossOrigin = "anonymous";
65
+ document.body.appendChild(script);
66
+
67
+ return () => {
68
+ document.body.removeChild(script);
69
+ };
70
+ }
71
+ }, [checkoutId]);
72
+
73
+ if (error) {
74
+ return <p>Error: {error}</p>;
75
+ }
76
+
77
+
78
+ if (isLoading) {
79
+ return <p>Loading...</p>;
80
+ }
81
+
82
+ if (checkoutId) {
83
+ return (
84
+ <form
85
+ action={redirectUrl}
86
+ className="paymentWidgets"
87
+ data-brands="VISA MASTER AMEX"
88
+ ></form>
89
+ );
90
+ }
91
+
92
+ return (
93
+ <div>
94
+ <p>No order</p>
95
+ </div>
96
+ );
97
+ };
98
+
99
+ export default HyperpayOrder;
@@ -0,0 +1,76 @@
1
+ import React from "react";
2
+ import { PayPalButtons, usePayPalScriptReducer } from "@paypal/react-paypal-js";
3
+ import backendConnector from "../shared/requests/backendConnector.js";
4
+
5
+ const Spinner = () => <div className="spinner">Processing payment...</div>;
6
+
7
+ const ButtonWrapper = ({
8
+ order,
9
+ onChange = () => {},
10
+ onStatusChange = () => {},
11
+ env,
12
+ }) => {
13
+ if (env !== "production" && env !== "development") {
14
+ return <div>Invalid Env</div>;
15
+ }
16
+ const [{ isPending }] = usePayPalScriptReducer();
17
+
18
+ const createOrderOrSubscription = async () => {
19
+ try {
20
+ const response = await backendConnector.createPaypalOrder(order, env);
21
+ onChange({ event: "createOrder", data: response });
22
+ return response.id;
23
+ } catch (error) {
24
+ console.error("Error creating PayPal transaction:", error);
25
+ throw new Error("Transaction creation failed");
26
+ }
27
+ };
28
+
29
+ const handleApproval = async (data, actions) => {
30
+ try {
31
+ console.log(data);
32
+ const captureData = {
33
+ orderId: data?.orderID || undefined,
34
+ subscriptionId: data?.subscriptionID || data?.id,
35
+ type: order.type,
36
+ };
37
+
38
+ await backendConnector.approveOrder(captureData, env);
39
+ if (order.type == "order") {
40
+ return actions.order.capture().then(function (details) {
41
+ onStatusChange(true);
42
+ onChange({ event: "approveOrder", data: data });
43
+
44
+ console.log(
45
+ "Transaction completed by " + details.payer.name.given_name
46
+ );
47
+ });
48
+ }
49
+ onStatusChange(true);
50
+ onChange({ event: "approveOrder", data: data });
51
+ } catch (error) {
52
+ console.error("Error capturing PayPal transaction:", error);
53
+ }
54
+ };
55
+
56
+ return (
57
+ <>
58
+ {isPending ? <Spinner /> : null}
59
+ <PayPalButtons
60
+ style={{ layout: "vertical" }}
61
+ disabled={false}
62
+ fundingSource={undefined}
63
+ createOrder={
64
+ order.type === "order" ? createOrderOrSubscription : undefined
65
+ }
66
+ createSubscription={
67
+ order.type === "subscription" ? createOrderOrSubscription : undefined
68
+ }
69
+ onError={(err) => console.log(err)}
70
+ onApprove={handleApproval}
71
+ />
72
+ </>
73
+ );
74
+ };
75
+
76
+ export default ButtonWrapper;
@@ -0,0 +1,32 @@
1
+ import React from "react";
2
+ import { PayPalScriptProvider } from "@paypal/react-paypal-js";
3
+ import ButtonWrapper from "./buttonWrapper.js";
4
+
5
+ const PaypalOrder = ({
6
+ currency = "USD",
7
+ clientId = "test",
8
+ order = {},
9
+ onChange = () => {},
10
+ onStatusChange = () => {},
11
+ env,
12
+ }) => {
13
+ const initialOptions = {
14
+ clientId: clientId,
15
+ currency: currency,
16
+ vault: order.type === "subscription",
17
+ };
18
+ return (
19
+ <div style={{ maxWidth: "750px", minHeight: "200px" }}>
20
+ <PayPalScriptProvider options={initialOptions}>
21
+ <ButtonWrapper
22
+ order={order}
23
+ onChange={onChange}
24
+ onStatusChange={onStatusChange}
25
+ env={env}
26
+ />
27
+ </PayPalScriptProvider>
28
+ </div>
29
+ );
30
+ };
31
+
32
+ export default PaypalOrder;
@@ -0,0 +1,12 @@
1
+ const config = {
2
+ development: {
3
+ BACKEND_BASE_URL: "http://localhost:5000/api",
4
+ HYPERPAY_BASE_URL: "https://eu-test.oppwa.com/",
5
+ },
6
+ production: {
7
+ BACKEND_BASE_URL: "http://prod:5000/api",
8
+ HYPERPAY_BASE_URL: "https://eu-prod.oppwa.com/",
9
+ },
10
+ };
11
+
12
+ export default config;
@@ -0,0 +1,16 @@
1
+ // Services
2
+ import backendConnector from "./requests/backendConnector";
3
+
4
+ class PaypalService {
5
+ async createOrder(data) {
6
+ const result = await backendConnector.createPaypalOrder(data);
7
+ if (result?.id) return result?.id;
8
+ }
9
+
10
+ async onApprove(data) {
11
+ const result = await backendConnector.approveOrder(data);
12
+ return result;
13
+ }
14
+ }
15
+
16
+ export default new PaypalService();
@@ -0,0 +1,24 @@
1
+ // Services
2
+ import request from "./request.js";
3
+
4
+ class BackendConnector {
5
+ async createPaypalOrder(data, env) {
6
+ const requestConfig = {
7
+ url: "/paypal/orders/create-order",
8
+ data,
9
+ };
10
+ const result = await request.post(requestConfig, env);
11
+ return result;
12
+ }
13
+
14
+ async approveOrder(data, env) {
15
+ const requestConfig = {
16
+ url: "/paypal/orders/capture-order",
17
+ data,
18
+ };
19
+ const result = await request.post(requestConfig, env);
20
+ return result;
21
+ }
22
+ }
23
+
24
+ export default new BackendConnector();
@@ -0,0 +1,59 @@
1
+ // Services
2
+ import config from "../config.js";
3
+ import request from "./request.js";
4
+
5
+ class HyperpayConnector {
6
+ constructor() {
7
+ this.BASEURL = config.production.HYPERPAY_BASE_URL;
8
+ this.DEV_BASEURL = config.development.HYPERPAY_BASE_URL;
9
+ }
10
+
11
+ defaultHeaders = (data) => {
12
+ const headers = {
13
+ "Content-Type": "application/x-www-form-urlencoded",
14
+ "Content-Length": data?.length,
15
+ // Authorization:
16
+ // "Bearer OGFjN2E0Yzc5Mzk0YmRjODAxOTM5NzM2ZjFhNzA2NDF8enlac1lYckc4QXk6bjYzI1NHNng=",
17
+ };
18
+
19
+ return headers;
20
+ };
21
+ async createHyperpayOrder(data, env) {
22
+ const headers = this.defaultHeaders();
23
+ const url = "/hyperpay/orders/create-order";
24
+ const requestConfig = {
25
+ url: url,
26
+ // baseUrl: env === "development" ? this.DEV_BASEURL : this.BASEURL,
27
+ data,
28
+ headers: headers,
29
+ };
30
+ console.log("requestConfig", requestConfig);
31
+ const result = await request.post(requestConfig ,env);
32
+ console.log("result", result);
33
+ return result;
34
+ }
35
+
36
+ async getOrderStatus(checkoutId, env = "production") {
37
+ const headers = this.defaultHeaders();
38
+ const requestConfig = {
39
+ url: `/hyperpay/orders/get-order/${checkoutId}`,
40
+ // baseUrl: env === "development" ? this.DEV_BASEURL : this.BASEURL,
41
+ headers,
42
+ };
43
+ const result = await request.get(requestConfig);
44
+ return result;
45
+ }
46
+
47
+ async captureOrder(orderId, env = "production") {
48
+ const headers = this.defaultHeaders();
49
+ const requestConfig = {
50
+ url: `/hyperpay/orders/capture-order/${orderId}`,
51
+ // baseUrl: env === "development" ? this.DEV_BASEURL : this.BASEURL,
52
+ headers,
53
+ };
54
+ const result = await request.post(requestConfig);
55
+ return result;
56
+ }
57
+ }
58
+
59
+ export default new HyperpayConnector();
@@ -0,0 +1,90 @@
1
+ import axios from "axios";
2
+ // CONFIG
3
+ import config from "../config.js";
4
+
5
+ class Request {
6
+ constructor() {}
7
+
8
+ async handleRequests(finalConfig, env) {
9
+ try {
10
+ axios.defaults.baseURL = config[env].BACKEND_BASE_URL;
11
+ const response = await axios.request(finalConfig);
12
+
13
+ return response.data;
14
+ } catch (err) {
15
+ console.log("err", err);
16
+ if (err.response) {
17
+ if (err.response.status === 401) {
18
+ return (window.location.href = "/login");
19
+ }
20
+ return err.response.data;
21
+ } else if (err.request) {
22
+ return {
23
+ success: false,
24
+ message: "No response received, please try again later.",
25
+ };
26
+ } else {
27
+
28
+ return { success: false, message: "An unexpected error occurred." };
29
+ }
30
+ }
31
+ }
32
+
33
+ async post(config, env) {
34
+ const defaultConfig = {
35
+ method: "post",
36
+ };
37
+
38
+ const finalConfig = {
39
+ ...defaultConfig,
40
+ ...config,
41
+ };
42
+ return await this.handleRequests(finalConfig, env);
43
+ }
44
+
45
+ async get(config = {}, env) {
46
+ const defaultConfig = {
47
+ method: "get",
48
+ };
49
+ const finalConfig = {
50
+ ...defaultConfig,
51
+ ...config,
52
+ };
53
+ return await this.handleRequests(finalConfig, env);
54
+ }
55
+
56
+ async put(config, env) {
57
+ const defaultConfig = {
58
+ method: "put",
59
+ };
60
+ const finalConfig = {
61
+ ...defaultConfig,
62
+ ...config,
63
+ };
64
+ return await this.handleRequests(finalConfig, env);
65
+ }
66
+
67
+ async patch(config, env) {
68
+ const defaultConfig = {
69
+ method: "patch",
70
+ };
71
+ const finalConfig = {
72
+ ...defaultConfig,
73
+ ...config,
74
+ };
75
+ return await this.handleRequests(finalConfig, env);
76
+ }
77
+
78
+ async delete(config, env) {
79
+ const defaultConfig = {
80
+ method: "delete",
81
+ };
82
+ const finalConfig = {
83
+ ...defaultConfig,
84
+ ...config,
85
+ };
86
+ return await this.handleRequests(finalConfig, env);
87
+ }
88
+ }
89
+
90
+ export default new Request();
@@ -0,0 +1,46 @@
1
+ // webpack.config.js
2
+ import path from "path";
3
+ import Dotenv from "dotenv-webpack";
4
+
5
+ const isProduction = process.env.NODE_ENV === "production";
6
+
7
+ const config = {
8
+ entry: "./index.js",
9
+ output: {
10
+ path: path.resolve("build"),
11
+ filename: "index.js",
12
+ },
13
+ devServer: {
14
+ open: true,
15
+ host: "localhost",
16
+ },
17
+ module: {
18
+ rules: [
19
+ {
20
+ test: /\.(js|jsx)$/i,
21
+ loader: "babel-loader",
22
+ },
23
+ {
24
+ test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
25
+ type: "asset",
26
+ },
27
+ ],
28
+ },
29
+ plugins: [
30
+ new Dotenv({
31
+ path: "./.env",
32
+ // Use `true` for production mode (only load .env)
33
+ // Use `false` for development mode (load .env and .env.local)
34
+ safe: isProduction ? true : false,
35
+ }),
36
+ ],
37
+ };
38
+
39
+ export default () => {
40
+ if (isProduction) {
41
+ config.mode = "production";
42
+ } else {
43
+ config.mode = "development";
44
+ }
45
+ return config;
46
+ };