@zezosoft/react-native-zezopay 1.0.0
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/LICENSE +21 -0
- package/README.md +150 -0
- package/lib/module/ZezoPay/Payments/Providers/PaymentGateways.types.d.js +2 -0
- package/lib/module/ZezoPay/Payments/Providers/PaymentGateways.types.d.js.map +1 -0
- package/lib/module/ZezoPay/Payments/Providers/Razorpay/Razorpay.js +39 -0
- package/lib/module/ZezoPay/Payments/Providers/Razorpay/Razorpay.js.map +1 -0
- package/lib/module/ZezoPay/Payments/Providers/index.js +10 -0
- package/lib/module/ZezoPay/Payments/Providers/index.js.map +1 -0
- package/lib/module/ZezoPay/ZezoPay.js +176 -0
- package/lib/module/ZezoPay/ZezoPay.js.map +1 -0
- package/lib/module/ZezoPay/components/Header.js +97 -0
- package/lib/module/ZezoPay/components/Header.js.map +1 -0
- package/lib/module/ZezoPay/components/PayButton.js +143 -0
- package/lib/module/ZezoPay/components/PayButton.js.map +1 -0
- package/lib/module/ZezoPay/components/PaymentMethod.js +250 -0
- package/lib/module/ZezoPay/components/PaymentMethod.js.map +1 -0
- package/lib/module/ZezoPay/components/Summary.js +184 -0
- package/lib/module/ZezoPay/components/Summary.js.map +1 -0
- package/lib/module/ZezoPay/components/VoucherBox.js +124 -0
- package/lib/module/ZezoPay/components/VoucherBox.js.map +1 -0
- package/lib/module/ZezoPay/index.js +5 -0
- package/lib/module/ZezoPay/index.js.map +1 -0
- package/lib/module/ZezoPay/types/index.js +4 -0
- package/lib/module/ZezoPay/types/index.js.map +1 -0
- package/lib/module/ZezoPay/utils/hooks/useAsync.js +32 -0
- package/lib/module/ZezoPay/utils/hooks/useAsync.js.map +1 -0
- package/lib/module/ZezoPay/utils/hooks/useZezoPay.js +270 -0
- package/lib/module/ZezoPay/utils/hooks/useZezoPay.js.map +1 -0
- package/lib/module/ZezoPay/utils/index.js +15 -0
- package/lib/module/ZezoPay/utils/index.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/ZezoPay/Payments/Providers/Razorpay/Razorpay.d.ts +7 -0
- package/lib/typescript/src/ZezoPay/Payments/Providers/Razorpay/Razorpay.d.ts.map +1 -0
- package/lib/typescript/src/ZezoPay/Payments/Providers/index.d.ts +7 -0
- package/lib/typescript/src/ZezoPay/Payments/Providers/index.d.ts.map +1 -0
- package/lib/typescript/src/ZezoPay/ZezoPay.d.ts +5 -0
- package/lib/typescript/src/ZezoPay/ZezoPay.d.ts.map +1 -0
- package/lib/typescript/src/ZezoPay/components/Header.d.ts +12 -0
- package/lib/typescript/src/ZezoPay/components/Header.d.ts.map +1 -0
- package/lib/typescript/src/ZezoPay/components/PayButton.d.ts +12 -0
- package/lib/typescript/src/ZezoPay/components/PayButton.d.ts.map +1 -0
- package/lib/typescript/src/ZezoPay/components/PaymentMethod.d.ts +12 -0
- package/lib/typescript/src/ZezoPay/components/PaymentMethod.d.ts.map +1 -0
- package/lib/typescript/src/ZezoPay/components/Summary.d.ts +7 -0
- package/lib/typescript/src/ZezoPay/components/Summary.d.ts.map +1 -0
- package/lib/typescript/src/ZezoPay/components/VoucherBox.d.ts +9 -0
- package/lib/typescript/src/ZezoPay/components/VoucherBox.d.ts.map +1 -0
- package/lib/typescript/src/ZezoPay/index.d.ts +3 -0
- package/lib/typescript/src/ZezoPay/index.d.ts.map +1 -0
- package/lib/typescript/src/ZezoPay/types/index.d.ts +65 -0
- package/lib/typescript/src/ZezoPay/types/index.d.ts.map +1 -0
- package/lib/typescript/src/ZezoPay/utils/hooks/useAsync.d.ts +6 -0
- package/lib/typescript/src/ZezoPay/utils/hooks/useAsync.d.ts.map +1 -0
- package/lib/typescript/src/ZezoPay/utils/hooks/useZezoPay.d.ts +46 -0
- package/lib/typescript/src/ZezoPay/utils/hooks/useZezoPay.d.ts.map +1 -0
- package/lib/typescript/src/ZezoPay/utils/index.d.ts +6 -0
- package/lib/typescript/src/ZezoPay/utils/index.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +2 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +181 -0
- package/src/ZezoPay/Payments/Providers/PaymentGateways.types.d.ts +48 -0
- package/src/ZezoPay/Payments/Providers/Razorpay/Razorpay.ts +46 -0
- package/src/ZezoPay/Payments/Providers/index.ts +8 -0
- package/src/ZezoPay/ZezoPay.tsx +174 -0
- package/src/ZezoPay/components/Header.tsx +107 -0
- package/src/ZezoPay/components/PayButton.tsx +132 -0
- package/src/ZezoPay/components/PaymentMethod.tsx +259 -0
- package/src/ZezoPay/components/Summary.tsx +188 -0
- package/src/ZezoPay/components/VoucherBox.tsx +133 -0
- package/src/ZezoPay/index.ts +2 -0
- package/src/ZezoPay/types/index.ts +69 -0
- package/src/ZezoPay/utils/hooks/useAsync.ts +38 -0
- package/src/ZezoPay/utils/hooks/useZezoPay.ts +325 -0
- package/src/ZezoPay/utils/index.ts +16 -0
- package/src/index.tsx +1 -0
package/package.json
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zezosoft/react-native-zezopay",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A React Native library for integrating ZezoPay payment gateway seamlessly in iOS and Android apps.",
|
|
5
|
+
"main": "./lib/module/index.js",
|
|
6
|
+
"types": "./lib/typescript/src/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"source": "./src/index.tsx",
|
|
10
|
+
"types": "./lib/typescript/src/index.d.ts",
|
|
11
|
+
"default": "./lib/module/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"src",
|
|
17
|
+
"lib",
|
|
18
|
+
"android",
|
|
19
|
+
"ios",
|
|
20
|
+
"cpp",
|
|
21
|
+
"*.podspec",
|
|
22
|
+
"react-native.config.js",
|
|
23
|
+
"!ios/build",
|
|
24
|
+
"!android/build",
|
|
25
|
+
"!android/gradle",
|
|
26
|
+
"!android/gradlew",
|
|
27
|
+
"!android/gradlew.bat",
|
|
28
|
+
"!android/local.properties",
|
|
29
|
+
"!**/__tests__",
|
|
30
|
+
"!**/__fixtures__",
|
|
31
|
+
"!**/__mocks__",
|
|
32
|
+
"!**/.*"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"example": "yarn workspace @zezosoft/react-native-zezopay-example",
|
|
36
|
+
"test": "jest",
|
|
37
|
+
"typecheck": "tsc",
|
|
38
|
+
"lint": "eslint \"**/*.{js,ts,tsx}\"",
|
|
39
|
+
"lint:fix": "eslint \"**/*.{js,ts,tsx}\" --fix",
|
|
40
|
+
"clean": "del-cli lib",
|
|
41
|
+
"prepare": "bob build",
|
|
42
|
+
"release": "release-it --only-version",
|
|
43
|
+
"build": "bob build",
|
|
44
|
+
"watch": "nodemon --watch src --ext ts,tsx,js --delay 500ms --exec \"yarn clean && yarn build && yalc push\""
|
|
45
|
+
},
|
|
46
|
+
"keywords": [
|
|
47
|
+
"react-native",
|
|
48
|
+
"zezopay",
|
|
49
|
+
"payment",
|
|
50
|
+
"payment-gateway",
|
|
51
|
+
"ios",
|
|
52
|
+
"android",
|
|
53
|
+
"upi",
|
|
54
|
+
"razorpay",
|
|
55
|
+
"library"
|
|
56
|
+
],
|
|
57
|
+
"repository": {
|
|
58
|
+
"type": "git",
|
|
59
|
+
"url": "git+https://github.com/Zezo-Soft/react-native-zezopay.git"
|
|
60
|
+
},
|
|
61
|
+
"author": "Naresh Dhamu <narsadhamu@gmail.com> (https://github.com/naresh-dhamu)",
|
|
62
|
+
"license": "MIT",
|
|
63
|
+
"bugs": {
|
|
64
|
+
"url": "https://github.com/Zezo-Soft/react-native-zezopay/issues"
|
|
65
|
+
},
|
|
66
|
+
"homepage": "https://github.com/Zezo-Soft/react-native-zezopay#readme",
|
|
67
|
+
"publishConfig": {
|
|
68
|
+
"registry": "https://registry.npmjs.org/"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@commitlint/config-conventional": "^19.6.0",
|
|
72
|
+
"@eslint/compat": "^1.2.7",
|
|
73
|
+
"@eslint/eslintrc": "^3.3.0",
|
|
74
|
+
"@eslint/js": "^9.22.0",
|
|
75
|
+
"@evilmartians/lefthook": "^1.5.0",
|
|
76
|
+
"@react-native/babel-preset": "0.78.2",
|
|
77
|
+
"@react-native/eslint-config": "^0.78.0",
|
|
78
|
+
"@release-it/conventional-changelog": "^9.0.2",
|
|
79
|
+
"@types/axios": "^0.14.4",
|
|
80
|
+
"@types/jest": "^29.5.5",
|
|
81
|
+
"@types/react": "^19.0.12",
|
|
82
|
+
"@types/react-native-razorpay": "^2.2.6",
|
|
83
|
+
"commitlint": "^19.6.1",
|
|
84
|
+
"del-cli": "^6.0.0",
|
|
85
|
+
"eslint": "^9.22.0",
|
|
86
|
+
"eslint-config-prettier": "^10.1.1",
|
|
87
|
+
"eslint-plugin-prettier": "^5.2.3",
|
|
88
|
+
"jest": "^29.7.0",
|
|
89
|
+
"nodemon": "^3.1.10",
|
|
90
|
+
"prettier": "^3.0.3",
|
|
91
|
+
"react": "19.0.0",
|
|
92
|
+
"react-native": "0.79.5",
|
|
93
|
+
"react-native-builder-bob": "^0.40.13",
|
|
94
|
+
"react-native-linear-gradient": "^2.8.3",
|
|
95
|
+
"react-native-safe-area-context": "^5.6.1",
|
|
96
|
+
"react-native-svg": "^15.13.0",
|
|
97
|
+
"release-it": "^17.10.0",
|
|
98
|
+
"typescript": "5.4.4",
|
|
99
|
+
"yalc": "^1.0.0-pre.53"
|
|
100
|
+
},
|
|
101
|
+
"peerDependencies": {
|
|
102
|
+
"react": "*",
|
|
103
|
+
"react-native": "*",
|
|
104
|
+
"react-native-linear-gradient": "*",
|
|
105
|
+
"react-native-safe-area-context": "*"
|
|
106
|
+
},
|
|
107
|
+
"workspaces": [
|
|
108
|
+
"example"
|
|
109
|
+
],
|
|
110
|
+
"packageManager": "yarn@3.6.1",
|
|
111
|
+
"jest": {
|
|
112
|
+
"preset": "react-native",
|
|
113
|
+
"modulePathIgnorePatterns": [
|
|
114
|
+
"<rootDir>/example/node_modules",
|
|
115
|
+
"<rootDir>/lib/"
|
|
116
|
+
]
|
|
117
|
+
},
|
|
118
|
+
"commitlint": {
|
|
119
|
+
"extends": [
|
|
120
|
+
"@commitlint/config-conventional"
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
"release-it": {
|
|
124
|
+
"git": {
|
|
125
|
+
"commitMessage": "chore: release ${version}",
|
|
126
|
+
"tagName": "v${version}"
|
|
127
|
+
},
|
|
128
|
+
"npm": {
|
|
129
|
+
"publish": true
|
|
130
|
+
},
|
|
131
|
+
"github": {
|
|
132
|
+
"release": true
|
|
133
|
+
},
|
|
134
|
+
"plugins": {
|
|
135
|
+
"@release-it/conventional-changelog": {
|
|
136
|
+
"preset": {
|
|
137
|
+
"name": "angular"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"prettier": {
|
|
143
|
+
"quoteProps": "consistent",
|
|
144
|
+
"singleQuote": true,
|
|
145
|
+
"tabWidth": 2,
|
|
146
|
+
"trailingComma": "es5",
|
|
147
|
+
"useTabs": false
|
|
148
|
+
},
|
|
149
|
+
"react-native-builder-bob": {
|
|
150
|
+
"source": "src",
|
|
151
|
+
"output": "lib",
|
|
152
|
+
"targets": [
|
|
153
|
+
[
|
|
154
|
+
"module",
|
|
155
|
+
{
|
|
156
|
+
"esm": true
|
|
157
|
+
}
|
|
158
|
+
],
|
|
159
|
+
[
|
|
160
|
+
"typescript",
|
|
161
|
+
{
|
|
162
|
+
"project": "tsconfig.build.json"
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
]
|
|
166
|
+
},
|
|
167
|
+
"create-react-native-library": {
|
|
168
|
+
"languages": "js",
|
|
169
|
+
"type": "library",
|
|
170
|
+
"version": "0.52.1"
|
|
171
|
+
},
|
|
172
|
+
"dependencies": {
|
|
173
|
+
"@zezosoft/zezopay-client": "^1.0.1",
|
|
174
|
+
"axios": "^1.11.0",
|
|
175
|
+
"lucide-react-native": "^0.542.0",
|
|
176
|
+
"qs": "^6.14.0",
|
|
177
|
+
"react-native-keyboard-aware-scroll-view": "^0.9.5",
|
|
178
|
+
"react-native-razorpay": "^2.3.0",
|
|
179
|
+
"react-native-size-matters": "^0.4.2"
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Naresh Dhamu
|
|
3
|
+
* @lastModified Thu 25 Sep 2025 at 11:35 AM
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
declare interface IPaymentGateway {
|
|
7
|
+
init(): void;
|
|
8
|
+
open(options: IPaymentGatewayOpenOptions): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare interface IPaymentGatewayOpenOptions {
|
|
12
|
+
publicKey: string;
|
|
13
|
+
amount: number;
|
|
14
|
+
currency: string;
|
|
15
|
+
order_id: string;
|
|
16
|
+
redirect_url?: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
mode?: 'live' | 'test';
|
|
20
|
+
image?: string;
|
|
21
|
+
handler?: (response: {
|
|
22
|
+
razorpay_order_id: string;
|
|
23
|
+
razorpay_signature?: string;
|
|
24
|
+
razorpay_payment_id?: string;
|
|
25
|
+
}) => void;
|
|
26
|
+
OnError?: (error?: any) => void;
|
|
27
|
+
prefill?: {
|
|
28
|
+
user_name?: string;
|
|
29
|
+
user_email?: string;
|
|
30
|
+
user_phone?: string;
|
|
31
|
+
};
|
|
32
|
+
theme?: {
|
|
33
|
+
color?: string;
|
|
34
|
+
};
|
|
35
|
+
extraData?: {
|
|
36
|
+
merchantId: string;
|
|
37
|
+
merchantTransactionId: string;
|
|
38
|
+
body: string;
|
|
39
|
+
checksum: string;
|
|
40
|
+
instrumentResponse?: {
|
|
41
|
+
type: string;
|
|
42
|
+
redirectInfo: {
|
|
43
|
+
url: string;
|
|
44
|
+
method: string;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Naresh Dhamu
|
|
3
|
+
* @lastModified Thu 25 Sep 2025 at 11:34 AM
|
|
4
|
+
*/
|
|
5
|
+
import RazorpayCheckout from 'react-native-razorpay';
|
|
6
|
+
|
|
7
|
+
class Razorpay implements IPaymentGateway {
|
|
8
|
+
constructor() {
|
|
9
|
+
// init Razorpay
|
|
10
|
+
this.init();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
init() {
|
|
14
|
+
// check if Razorpay already initialized
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async open(options: IPaymentGatewayOpenOptions) {
|
|
18
|
+
RazorpayCheckout.open({
|
|
19
|
+
key: options.publicKey,
|
|
20
|
+
amount: options.amount,
|
|
21
|
+
currency: options.currency,
|
|
22
|
+
name: options.name || '',
|
|
23
|
+
description: options.description
|
|
24
|
+
? options.description?.length > 255
|
|
25
|
+
? options.description.slice(0, 255)
|
|
26
|
+
: options.description
|
|
27
|
+
: '',
|
|
28
|
+
order_id: options.order_id,
|
|
29
|
+
image: options.image,
|
|
30
|
+
prefill: {
|
|
31
|
+
name: options?.prefill?.user_name || '',
|
|
32
|
+
email: options?.prefill?.user_email || '',
|
|
33
|
+
contact: options?.prefill?.user_phone || '',
|
|
34
|
+
},
|
|
35
|
+
theme: options.theme,
|
|
36
|
+
})
|
|
37
|
+
.then((response) => {
|
|
38
|
+
options.handler?.(response);
|
|
39
|
+
})
|
|
40
|
+
.catch((error) => {
|
|
41
|
+
options.OnError?.(error);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default Razorpay;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
Keyboard,
|
|
6
|
+
TouchableWithoutFeedback,
|
|
7
|
+
StatusBar,
|
|
8
|
+
Text,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
import { ArrowLeft } from 'lucide-react-native';
|
|
11
|
+
import { scale, verticalScale, moderateScale } from 'react-native-size-matters';
|
|
12
|
+
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
|
|
13
|
+
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
|
|
14
|
+
import Header from './components/Header';
|
|
15
|
+
import type { ZezoPayProps } from './types';
|
|
16
|
+
import PaymentMethod from './components/PaymentMethod';
|
|
17
|
+
import { Summary } from './components/Summary';
|
|
18
|
+
import PayButton from './components/PayButton';
|
|
19
|
+
import { useZezoPay } from './utils/hooks/useZezoPay';
|
|
20
|
+
import { formatCurrency } from './utils';
|
|
21
|
+
|
|
22
|
+
const ZezoPay: React.FC<ZezoPayProps> = ({
|
|
23
|
+
title = 'Payments',
|
|
24
|
+
summaryItems,
|
|
25
|
+
onBack,
|
|
26
|
+
userInfo,
|
|
27
|
+
publicKey,
|
|
28
|
+
digitalProductId,
|
|
29
|
+
subscriptionId,
|
|
30
|
+
callback,
|
|
31
|
+
}) => {
|
|
32
|
+
const {
|
|
33
|
+
selectedPayment,
|
|
34
|
+
setSelectedPayment,
|
|
35
|
+
summaryItems: items,
|
|
36
|
+
totalPrice,
|
|
37
|
+
isSuccess,
|
|
38
|
+
error,
|
|
39
|
+
isProcessing,
|
|
40
|
+
providers,
|
|
41
|
+
loading,
|
|
42
|
+
providerError,
|
|
43
|
+
removeItem,
|
|
44
|
+
handlePayNow,
|
|
45
|
+
} = useZezoPay({
|
|
46
|
+
publicKey: publicKey,
|
|
47
|
+
userInfo: {
|
|
48
|
+
_id: userInfo._id,
|
|
49
|
+
name: userInfo?.name || '',
|
|
50
|
+
email: userInfo?.email || '',
|
|
51
|
+
},
|
|
52
|
+
subscriptionId: subscriptionId,
|
|
53
|
+
digitalProductId: digitalProductId,
|
|
54
|
+
summaryItems: summaryItems || [],
|
|
55
|
+
callback,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<SafeAreaProvider>
|
|
60
|
+
<SafeAreaView style={styles.safeArea} edges={['bottom', 'left', 'right']}>
|
|
61
|
+
<StatusBar
|
|
62
|
+
barStyle="dark-content"
|
|
63
|
+
backgroundColor={styles.safeArea.backgroundColor}
|
|
64
|
+
/>
|
|
65
|
+
<SafeAreaView style={styles.headerSafeArea} edges={['top']}>
|
|
66
|
+
<View style={styles.headerWrapper}>
|
|
67
|
+
<Header
|
|
68
|
+
title={title}
|
|
69
|
+
onBack={onBack}
|
|
70
|
+
leftIcon={<ArrowLeft size={moderateScale(24)} color="#000" />}
|
|
71
|
+
/>
|
|
72
|
+
</View>
|
|
73
|
+
</SafeAreaView>
|
|
74
|
+
|
|
75
|
+
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
|
|
76
|
+
<View style={styles.container}>
|
|
77
|
+
<KeyboardAwareScrollView
|
|
78
|
+
style={styles.scrollView}
|
|
79
|
+
contentContainerStyle={styles.scrollContent}
|
|
80
|
+
keyboardShouldPersistTaps="handled"
|
|
81
|
+
enableOnAndroid
|
|
82
|
+
extraScrollHeight={verticalScale(20)}
|
|
83
|
+
showsVerticalScrollIndicator={false}
|
|
84
|
+
contentInsetAdjustmentBehavior="never"
|
|
85
|
+
>
|
|
86
|
+
<View style={styles.content}>
|
|
87
|
+
<PaymentMethod
|
|
88
|
+
providers={providers || []}
|
|
89
|
+
onProviderChange={setSelectedPayment}
|
|
90
|
+
selectedProvider={selectedPayment}
|
|
91
|
+
isLoading={loading}
|
|
92
|
+
error={providerError?.message}
|
|
93
|
+
/>
|
|
94
|
+
|
|
95
|
+
<Summary items={items} onRemoveItem={removeItem} />
|
|
96
|
+
</View>
|
|
97
|
+
</KeyboardAwareScrollView>
|
|
98
|
+
|
|
99
|
+
{/* Bottom container for error + PayButton */}
|
|
100
|
+
<View style={styles.bottomContainer}>
|
|
101
|
+
{error ? (
|
|
102
|
+
<View style={styles.errorWrapper}>
|
|
103
|
+
<Text style={styles.errorText}>{error}</Text>
|
|
104
|
+
</View>
|
|
105
|
+
) : null}
|
|
106
|
+
|
|
107
|
+
<PayButton
|
|
108
|
+
onPaymentInitiate={handlePayNow}
|
|
109
|
+
status={
|
|
110
|
+
isSuccess
|
|
111
|
+
? 'success'
|
|
112
|
+
: isProcessing
|
|
113
|
+
? 'processing'
|
|
114
|
+
: !selectedPayment || totalPrice === 0
|
|
115
|
+
? 'disabled'
|
|
116
|
+
: 'idle'
|
|
117
|
+
}
|
|
118
|
+
paymentButtonText={`Pay ${formatCurrency({
|
|
119
|
+
amount: totalPrice,
|
|
120
|
+
minimumFractionDigits: 0,
|
|
121
|
+
})}`}
|
|
122
|
+
noteText="Powered by Zezo Pay"
|
|
123
|
+
/>
|
|
124
|
+
</View>
|
|
125
|
+
</View>
|
|
126
|
+
</TouchableWithoutFeedback>
|
|
127
|
+
</SafeAreaView>
|
|
128
|
+
</SafeAreaProvider>
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const styles = StyleSheet.create({
|
|
133
|
+
safeArea: { flex: 1, backgroundColor: '#FFFFFF' },
|
|
134
|
+
headerSafeArea: { backgroundColor: '#FFFFFF' },
|
|
135
|
+
headerWrapper: {
|
|
136
|
+
borderBottomWidth: 1,
|
|
137
|
+
borderBottomColor: '#E5E7EB',
|
|
138
|
+
zIndex: 10,
|
|
139
|
+
},
|
|
140
|
+
container: { flex: 1, position: 'relative' },
|
|
141
|
+
scrollView: { flex: 1, paddingBottom: verticalScale(80) },
|
|
142
|
+
scrollContent: {
|
|
143
|
+
flexGrow: 1,
|
|
144
|
+
paddingTop: verticalScale(10),
|
|
145
|
+
paddingBottom: verticalScale(80),
|
|
146
|
+
},
|
|
147
|
+
content: { paddingHorizontal: scale(16) },
|
|
148
|
+
bottomContainer: {
|
|
149
|
+
position: 'absolute',
|
|
150
|
+
bottom: 0,
|
|
151
|
+
left: 0,
|
|
152
|
+
right: 0,
|
|
153
|
+
paddingHorizontal: scale(16),
|
|
154
|
+
paddingVertical: verticalScale(16),
|
|
155
|
+
backgroundColor: '#FFFFFF',
|
|
156
|
+
borderTopWidth: 1,
|
|
157
|
+
borderTopColor: '#E5E7EB',
|
|
158
|
+
alignItems: 'center',
|
|
159
|
+
zIndex: 5,
|
|
160
|
+
},
|
|
161
|
+
errorWrapper: {
|
|
162
|
+
marginBottom: verticalScale(8),
|
|
163
|
+
width: '100%',
|
|
164
|
+
alignItems: 'center',
|
|
165
|
+
},
|
|
166
|
+
errorText: {
|
|
167
|
+
color: '#DC2626',
|
|
168
|
+
fontSize: moderateScale(14),
|
|
169
|
+
fontWeight: '500',
|
|
170
|
+
textAlign: 'center',
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
export default ZezoPay;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Text, Pressable, StyleSheet, Platform } from 'react-native';
|
|
3
|
+
import type { ViewStyle, TextStyle } from 'react-native';
|
|
4
|
+
import { ArrowLeft } from 'lucide-react-native';
|
|
5
|
+
import { scale, moderateScale } from 'react-native-size-matters';
|
|
6
|
+
|
|
7
|
+
export interface HeaderProps {
|
|
8
|
+
title: string;
|
|
9
|
+
titleStyle?: TextStyle;
|
|
10
|
+
containerStyle?: ViewStyle;
|
|
11
|
+
leftIcon?: React.ReactNode;
|
|
12
|
+
onBack?: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const Header: React.FC<HeaderProps> = ({
|
|
16
|
+
title,
|
|
17
|
+
titleStyle,
|
|
18
|
+
containerStyle,
|
|
19
|
+
leftIcon,
|
|
20
|
+
onBack,
|
|
21
|
+
}) => {
|
|
22
|
+
return (
|
|
23
|
+
<View style={[styles.header, containerStyle]}>
|
|
24
|
+
{/* Left Button Container */}
|
|
25
|
+
<View style={styles.gridItemLeft}>
|
|
26
|
+
<View style={styles.backBtnContainer}>
|
|
27
|
+
<Pressable
|
|
28
|
+
onPress={onBack}
|
|
29
|
+
android_ripple={{
|
|
30
|
+
color: 'rgba(0,0,0,0.1)',
|
|
31
|
+
borderless: false,
|
|
32
|
+
radius: scale(100),
|
|
33
|
+
}}
|
|
34
|
+
style={({ pressed }) => [
|
|
35
|
+
styles.backBtnWrapper,
|
|
36
|
+
pressed && Platform.OS === 'ios' && styles.backBtnPressed,
|
|
37
|
+
]}
|
|
38
|
+
hitSlop={10}
|
|
39
|
+
>
|
|
40
|
+
<View style={styles.backBtn}>
|
|
41
|
+
{leftIcon ? (
|
|
42
|
+
leftIcon
|
|
43
|
+
) : (
|
|
44
|
+
<ArrowLeft size={moderateScale(20)} color="#000" />
|
|
45
|
+
)}
|
|
46
|
+
</View>
|
|
47
|
+
</Pressable>
|
|
48
|
+
</View>
|
|
49
|
+
</View>
|
|
50
|
+
|
|
51
|
+
{/* Title */}
|
|
52
|
+
<View style={styles.gridItem}>
|
|
53
|
+
<Text style={[styles.title, titleStyle]} numberOfLines={1}>
|
|
54
|
+
{title}
|
|
55
|
+
</Text>
|
|
56
|
+
</View>
|
|
57
|
+
|
|
58
|
+
<View style={styles.gridItem} />
|
|
59
|
+
</View>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const styles = StyleSheet.create({
|
|
64
|
+
header: {
|
|
65
|
+
flexDirection: 'row',
|
|
66
|
+
alignItems: 'center',
|
|
67
|
+
width: '100%',
|
|
68
|
+
height: scale(44),
|
|
69
|
+
paddingHorizontal: scale(16),
|
|
70
|
+
justifyContent: 'space-between',
|
|
71
|
+
},
|
|
72
|
+
gridItem: {
|
|
73
|
+
flex: 1,
|
|
74
|
+
alignItems: 'center',
|
|
75
|
+
justifyContent: 'center',
|
|
76
|
+
},
|
|
77
|
+
gridItemLeft: {
|
|
78
|
+
flex: 1,
|
|
79
|
+
alignItems: 'flex-start',
|
|
80
|
+
justifyContent: 'center',
|
|
81
|
+
},
|
|
82
|
+
backBtnContainer: {
|
|
83
|
+
borderRadius: scale(100),
|
|
84
|
+
overflow: 'hidden', // crucial for Android ripple
|
|
85
|
+
},
|
|
86
|
+
backBtnWrapper: {
|
|
87
|
+
borderRadius: scale(100),
|
|
88
|
+
},
|
|
89
|
+
backBtn: {
|
|
90
|
+
justifyContent: 'center',
|
|
91
|
+
alignItems: 'center',
|
|
92
|
+
padding: scale(10),
|
|
93
|
+
width: scale(35),
|
|
94
|
+
height: scale(35),
|
|
95
|
+
},
|
|
96
|
+
backBtnPressed: {
|
|
97
|
+
backgroundColor: 'rgba(0,0,0,0.1)', // iOS pressed effect
|
|
98
|
+
},
|
|
99
|
+
title: {
|
|
100
|
+
fontSize: moderateScale(18),
|
|
101
|
+
fontWeight: '700',
|
|
102
|
+
color: '#000',
|
|
103
|
+
textAlign: 'center',
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
export default Header;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
Pressable,
|
|
6
|
+
StyleSheet,
|
|
7
|
+
ActivityIndicator,
|
|
8
|
+
} from 'react-native';
|
|
9
|
+
import { scale, verticalScale, moderateScale } from 'react-native-size-matters';
|
|
10
|
+
import LinearGradient from 'react-native-linear-gradient';
|
|
11
|
+
import { Check } from 'lucide-react-native';
|
|
12
|
+
|
|
13
|
+
interface PayButtonProps {
|
|
14
|
+
onPaymentInitiate: () => void;
|
|
15
|
+
status?: 'idle' | 'processing' | 'success' | 'disabled';
|
|
16
|
+
paymentButtonText?: string;
|
|
17
|
+
paymentProcessingText?: string;
|
|
18
|
+
paymentSuccessText?: string;
|
|
19
|
+
noteText?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const PayButton: React.FC<PayButtonProps> = ({
|
|
23
|
+
onPaymentInitiate,
|
|
24
|
+
status = 'idle',
|
|
25
|
+
paymentButtonText = 'Pay Now',
|
|
26
|
+
paymentProcessingText = 'Processing...',
|
|
27
|
+
paymentSuccessText = 'Payment Successful',
|
|
28
|
+
noteText = 'Powered by Zezo Pay',
|
|
29
|
+
}) => {
|
|
30
|
+
const colorsMap = {
|
|
31
|
+
idle: ['#0251ca', '#063482'],
|
|
32
|
+
processing: ['#0a84ff', '#1784e6'],
|
|
33
|
+
success: ['#28a745', '#1c7c31'],
|
|
34
|
+
disabled: ['#556fadff', '#3d71e9ff'],
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<View style={styles.container}>
|
|
39
|
+
{status === 'success' ? (
|
|
40
|
+
<View style={styles.shadowWrapper}>
|
|
41
|
+
<LinearGradient
|
|
42
|
+
colors={colorsMap.success}
|
|
43
|
+
start={{ x: 0, y: 0 }}
|
|
44
|
+
end={{ x: 1, y: 0 }}
|
|
45
|
+
style={styles.paymentButton}
|
|
46
|
+
>
|
|
47
|
+
<Check size={20} color="#fff" />
|
|
48
|
+
<Text style={[styles.successText, { marginLeft: scale(8) }]}>
|
|
49
|
+
{paymentSuccessText}
|
|
50
|
+
</Text>
|
|
51
|
+
</LinearGradient>
|
|
52
|
+
</View>
|
|
53
|
+
) : (
|
|
54
|
+
<Pressable
|
|
55
|
+
onPress={onPaymentInitiate}
|
|
56
|
+
disabled={status === 'processing' || status === 'disabled'}
|
|
57
|
+
style={({ pressed }) => [
|
|
58
|
+
{ opacity: pressed ? 0.85 : 1, width: '100%' },
|
|
59
|
+
]}
|
|
60
|
+
>
|
|
61
|
+
<View style={styles.shadowWrapper}>
|
|
62
|
+
<LinearGradient
|
|
63
|
+
colors={colorsMap[status]}
|
|
64
|
+
start={{ x: 0, y: 0 }}
|
|
65
|
+
end={{ x: 1, y: 0 }}
|
|
66
|
+
style={styles.paymentButton}
|
|
67
|
+
>
|
|
68
|
+
{status === 'processing' ? (
|
|
69
|
+
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
70
|
+
<ActivityIndicator
|
|
71
|
+
color="#fff"
|
|
72
|
+
style={{ marginRight: scale(8) }}
|
|
73
|
+
/>
|
|
74
|
+
<Text style={styles.paymentText}>
|
|
75
|
+
{paymentProcessingText}
|
|
76
|
+
</Text>
|
|
77
|
+
</View>
|
|
78
|
+
) : (
|
|
79
|
+
<Text style={styles.paymentText}>{paymentButtonText}</Text>
|
|
80
|
+
)}
|
|
81
|
+
</LinearGradient>
|
|
82
|
+
</View>
|
|
83
|
+
</Pressable>
|
|
84
|
+
)}
|
|
85
|
+
|
|
86
|
+
{noteText && <Text style={styles.noteText}>{noteText}</Text>}
|
|
87
|
+
</View>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const styles = StyleSheet.create({
|
|
92
|
+
container: { width: '100%', alignItems: 'center' },
|
|
93
|
+
shadowWrapper: {
|
|
94
|
+
width: '100%',
|
|
95
|
+
height: verticalScale(50),
|
|
96
|
+
borderRadius: scale(12),
|
|
97
|
+
shadowColor: '#000',
|
|
98
|
+
shadowOffset: { width: 0, height: 3 },
|
|
99
|
+
shadowOpacity: 0.2,
|
|
100
|
+
shadowRadius: 4,
|
|
101
|
+
elevation: 3,
|
|
102
|
+
backgroundColor: '#0000',
|
|
103
|
+
justifyContent: 'center',
|
|
104
|
+
},
|
|
105
|
+
paymentButton: {
|
|
106
|
+
width: '100%',
|
|
107
|
+
height: '100%',
|
|
108
|
+
borderRadius: scale(12),
|
|
109
|
+
justifyContent: 'center',
|
|
110
|
+
alignItems: 'center',
|
|
111
|
+
flexDirection: 'row',
|
|
112
|
+
},
|
|
113
|
+
paymentText: {
|
|
114
|
+
color: '#fff',
|
|
115
|
+
fontSize: moderateScale(18),
|
|
116
|
+
fontWeight: '700',
|
|
117
|
+
},
|
|
118
|
+
successText: {
|
|
119
|
+
color: '#fff',
|
|
120
|
+
fontSize: moderateScale(18),
|
|
121
|
+
fontWeight: '700',
|
|
122
|
+
},
|
|
123
|
+
noteText: {
|
|
124
|
+
marginTop: verticalScale(10),
|
|
125
|
+
fontSize: moderateScale(13),
|
|
126
|
+
fontWeight: '600',
|
|
127
|
+
color: '#FF7847',
|
|
128
|
+
textAlign: 'center',
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
export default PayButton;
|