razorpay-expo 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/README.md ADDED
@@ -0,0 +1,222 @@
1
+ # razorpay-expo
2
+
3
+ A modern, maintained Razorpay SDK for **Expo** and **React Native**.
4
+
5
+ Built as a community replacement for the outdated official Razorpay
6
+ React Native SDK.
7
+
8
+ <p align="center">
9
+ <img src="docs/demo.gif" alt="Razorpay Expo Demo" width="360" />
10
+ </p>
11
+
12
+ <p align="center">
13
+ <em>Quick demo of the Razorpay Expo SDK in action</em>
14
+ </p>
15
+
16
+ ---
17
+
18
+ ## ✨ Features
19
+
20
+ - Works with Expo (WebView-based)
21
+ - Modern API with hooks & provider
22
+ - No outdated native dependencies
23
+ - Designed for real production usage
24
+
25
+ ---
26
+
27
+ ## Installation
28
+
29
+ First, install the package and its peer dependencies:
30
+
31
+ ```bash
32
+ npm install razorpay-expo
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ There are two ways to use this library:
38
+
39
+ 1. **Provider & Hook Usage** (`<RazorpayProvider>` & `useRazorpay`) - **Preferred**.
40
+ 2. **Direct Component Usage** (`<RazorpayCheckout />`) - Manual state management.
41
+
42
+ ### Method 1: Provider & Hook (Recommended)
43
+
44
+ This approach lets you trigger checkout from anywhere in your app.
45
+
46
+ **1️⃣ Wrap your app with `RazorpayProvider`**
47
+
48
+ ```tsx
49
+ // _layout.tsx or App.tsx
50
+ import { RazorpayProvider } from "razorpay-expo";
51
+
52
+ export default function RootLayout() {
53
+ return (
54
+ <RazorpayProvider>
55
+ <Slot />
56
+ </RazorpayProvider>
57
+ );
58
+ }
59
+ ```
60
+
61
+ **2️⃣ Use `useRazorpay` in your components**
62
+
63
+ ```tsx
64
+ import React from "react";
65
+ import { Button } from "react-native";
66
+ import { useRazorpay } from "razorpay-expo";
67
+ import { useRouter } from "expo-router";
68
+
69
+ export default function PaymentScreen() {
70
+ const { openCheckout, closeCheckout } = useRazorpay();
71
+ const router = useRouter();
72
+
73
+ const handleBuy = async () => {
74
+ // 1. Create order on your backend
75
+ // const { orderId, currency, amount } = await createOrderOnBackend();
76
+
77
+ // For demo purposes:
78
+ const currency = "INR";
79
+ const amount = 100;
80
+ const orderId = "order_RPNBJhnTs2Lq0B"; // Replace with actual order_id from backend
81
+
82
+ openCheckout(
83
+ {
84
+ key: "YOUR_RAZORPAY_KEY",
85
+ currency: currency,
86
+ amount: amount,
87
+ order_id: orderId, // Mandatory: either order_id or subscription_id
88
+ name: "Test Company",
89
+ image: "https://codearcade.io/logos/logo.png",
90
+ description: "Test Transaction",
91
+ prefill: {
92
+ name: "John Doe",
93
+ email: "test@example.com",
94
+ contact: "1234567890",
95
+ },
96
+ theme: {
97
+ color: "#ffd35c",
98
+ },
99
+ },
100
+ {
101
+ onSuccess: (data) => {
102
+ console.log("Payment Success:", data);
103
+ closeCheckout();
104
+
105
+ // Navigate to success screen
106
+ router.replace({
107
+ pathname: "/success",
108
+ params: {
109
+ paymentId: data.razorpay_payment_id,
110
+ amount: amount.toString(),
111
+ date: new Date().toISOString(),
112
+ },
113
+ });
114
+ },
115
+ onFailure: (error) => {
116
+ console.log("Payment Failed:", error);
117
+ },
118
+ onClose: () => {
119
+ console.log("Widget closed");
120
+ },
121
+ },
122
+ );
123
+ };
124
+
125
+ return <Button title="Buy Now" onPress={handleBuy} />;
126
+ }
127
+ ```
128
+
129
+ ### Method 2: Direct Component Usage
130
+
131
+ Use RazorpayCheckout directly and control visibility yourself.
132
+
133
+ ```tsx
134
+ import React, { useState } from "react";
135
+ import { View, Text, Button, SafeAreaView } from "react-native";
136
+ import { RazorpayCheckout } from "razorpay-expo";
137
+
138
+ export default function App() {
139
+ const [open, setOpen] = useState(false);
140
+
141
+ return (
142
+ <SafeAreaView style={{ flex: 1 }}>
143
+ <View>
144
+ <Text>Home</Text>
145
+ <Button title="Buy Now" onPress={() => setOpen(true)} />
146
+
147
+ {open && (
148
+ <RazorpayCheckout
149
+ options={{
150
+ key: "YOUR_RAZORPAY_KEY", // e.g., rzp_test_...
151
+ currency: "INR",
152
+ amount: 100, // Amount in lowest denomination (e.g. 100 paise = 1 INR)
153
+ order_id: "order_RPNBJhnTs2Lq0B", // OR subscription_id
154
+ name: "Test Company",
155
+ image: "https://codearcade.io/logos/logo.png",
156
+ description: "Test Transaction",
157
+ prefill: {
158
+ name: "John Doe",
159
+ email: "test@example.com",
160
+ contact: "1234567890",
161
+ },
162
+ notes: {
163
+ order_id: "1",
164
+ payment_id: "1",
165
+ },
166
+ theme: {
167
+ color: "#ffd35c",
168
+ },
169
+ }}
170
+ onSuccess={(data) => console.log("Success:", data)}
171
+ onFailure={(error) => console.log("Failure:", error)}
172
+ onClose={() => setOpen(false)}
173
+ />
174
+ )}
175
+ </View>
176
+ </SafeAreaView>
177
+ );
178
+ }
179
+ ```
180
+
181
+ ## API Reference
182
+
183
+ ### `RazorpayCheckout` Props
184
+
185
+ | Prop | Type | Description |
186
+ | ----------- | ---------------------- | ---------------------------------------------------------------------- |
187
+ | `options` | `RazorpayOptions` | Configuration object for Razorpay checkout. |
188
+ | `onSuccess` | `(data: any) => void` | Callback function triggered on successful payment. |
189
+ | `onFailure` | `(error: any) => void` | Callback function triggered on payment failure. |
190
+ | `onClose` | `() => void` | Callback function triggered when the checkout close button is pressed. |
191
+
192
+ ### `useRazorpay` Hook
193
+
194
+ Returns:
195
+
196
+ - `openCheckout(options: RazorpayOptions, callbacks: RazorpayCallbacks)`: Function to open the checkout.
197
+ - `closeCheckout()`: Function to manually close the checkout (useful in `onSuccess`).
198
+
199
+ ### `RazorpayOptions`
200
+
201
+ | Field | Type | Required | Description |
202
+ | ----------------- | -------- | --------- | ----------------------------------------------------------------------------------------- |
203
+ | `key` | `string` | **Yes** | Your Razorpay Key ID. |
204
+ | `amount` | `number` | **Yes** | Amount in lowest currency unit (e.g., paise). |
205
+ | `currency` | `string` | **Yes** | Currency code (e.g., "INR"). |
206
+ | `order_id` | `string` | **Yes\*** | Order ID generated from backend. (\*Either `order_id` or `subscription_id` is mandatory). |
207
+ | `subscription_id` | `string` | **Yes\*** | Subscription ID for recurring payments. |
208
+ | `name` | `string` | No | Name of your company/app. |
209
+ | `description` | `string` | No | Description of the transaction. |
210
+ | `image` | `string` | No | URL to your logo. |
211
+ | `prefill` | `object` | No | Object containing `name`, `email`, `contact`. |
212
+ | `theme` | `object` | No | Object containing `color` (hex code). |
213
+
214
+ - Either order_id or subscription_id is required.
215
+
216
+ ⚠️ Disclaimer
217
+ This is an independent, community-maintained project and is not affiliated
218
+ with or endorsed by Razorpay or Expo.
219
+
220
+ ## License
221
+
222
+ MIT
@@ -0,0 +1,16 @@
1
+ import React, { ReactNode } from "react";
2
+ import { RazorpayOptions, RazorpaySuccessResponse, RazorpayErrorResponse } from "../types";
3
+ interface CheckoutCallbacks {
4
+ onSuccess: (data: RazorpaySuccessResponse) => void;
5
+ onFailure: (error: RazorpayErrorResponse["error"]) => void;
6
+ onClose?: () => void;
7
+ }
8
+ interface RazorpayContextType {
9
+ openCheckout: (options: RazorpayOptions, callbacks: CheckoutCallbacks) => void;
10
+ closeCheckout: () => void;
11
+ }
12
+ export declare const RazorpayProvider: ({ children }: {
13
+ children: ReactNode;
14
+ }) => React.JSX.Element;
15
+ export declare const useRazorpay: () => RazorpayContextType;
16
+ export {};
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import { RazorpayErrorResponse, RazorpayOptions, RazorpaySuccessResponse } from "../types";
3
+ interface RazorpayCheckoutProps {
4
+ options: RazorpayOptions;
5
+ onSuccess: (data: RazorpaySuccessResponse) => void;
6
+ onFailure: (error: RazorpayErrorResponse) => void;
7
+ onClose: () => void;
8
+ }
9
+ declare const RazorpayCheckout: ({ options, onSuccess, onFailure, onClose, }: RazorpayCheckoutProps) => React.JSX.Element;
10
+ export { RazorpayCheckout };
@@ -0,0 +1,3 @@
1
+ export * from "./components/provider";
2
+ export * from "./components/razorpayCheckout";
3
+ export type * from "./types";
package/dist/index.js ADDED
@@ -0,0 +1,49 @@
1
+ var j=Object.create;var{getPrototypeOf:y,defineProperty:x,getOwnPropertyNames:D}=Object;var p=Object.prototype.hasOwnProperty;var h=(f,d,g)=>{g=f!=null?j(y(f)):{};let _=d||!f||!f.__esModule?x(g,"default",{value:f,enumerable:!0}):g;for(let T of D(f))if(!p.call(_,T))x(_,T,{get:()=>f[T],enumerable:!0});return _};var Z=(f,d)=>()=>(d||f((d={exports:{}}).exports,d),d.exports);var F=((f)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(f,{get:(d,g)=>(typeof require<"u"?require:d)[g]}):f)(function(f){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+f+'" is not supported')});var H=Z((s,J)=>{function C(f){return f&&f.__esModule?f:{default:f}}J.exports=C,J.exports.__esModule=!0,J.exports.default=J.exports});var m=Z((N)=>{Object.defineProperty(N,"__esModule",{value:!0});N.default=void 0;var k=F("react-native"),u=k.StyleSheet.create({container:{flex:1,overflow:"hidden"},loadingOrErrorView:{position:"absolute",flex:1,justifyContent:"center",alignItems:"center",height:"100%",width:"100%",backgroundColor:"white"},loadingProgressBar:{height:20},errorText:{fontSize:14,textAlign:"center",marginBottom:2},errorTextTitle:{fontSize:15,fontWeight:"500",marginBottom:10},webView:{backgroundColor:"#ffffff"},flexStart:{alignSelf:"flex-start"},colorRed:{color:"red"}}),e=N.default=u});import*as l from"react";import*as $ from"react/jsx-runtime";var w=Z((U)=>{var A=H();Object.defineProperty(U,"__esModule",{value:!0});U.default=U.WebView=void 0;var df=A(l),q=F("react-native"),z=A(m()),V=U.WebView=function(){return $.jsx(q.View,{style:z.default.flexStart,children:$.jsx(q.Text,{style:z.default.colorRed,children:"React Native WebView does not support this platform."})})},gf=U.default=V});import{createContext as t,useContext as c,useState as L}from"react";import{StyleSheet as I,View as S,ActivityIndicator as n,Linking as o,Modal as i}from"react-native";var G=h(w(),1);import{jsxDEV as K}from"react/jsx-dev-runtime";var R=({options:f,onSuccess:d,onFailure:g,onClose:_})=>{let{handler:T,...M}=f,Y=`
2
+ <html>
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
+ <style>
6
+ body { display: flex; justify-content: center; align-items: center; background-color: transparent; }
7
+ </style>
8
+ </head>
9
+ <body>
10
+ <script src="https://checkout.razorpay.com/v1/checkout.js"></script>
11
+ <script>
12
+ // 1. Parse the options passed from React Native
13
+ var options = ${JSON.stringify(M)};
14
+
15
+ // 2. Attach the Success Handler
16
+ options.handler = function (response){
17
+ window.ReactNativeWebView.postMessage(JSON.stringify({
18
+ type: 'PAYMENT_SUCCESS',
19
+ data: response
20
+ }));
21
+ };
22
+
23
+ // 3. Attach Modal Dismiss (User closed the popup)
24
+ options.modal = {
25
+ ondismiss: function(){
26
+ window.ReactNativeWebView.postMessage(JSON.stringify({
27
+ type: 'PAYMENT_CLOSED'
28
+ }));
29
+ }
30
+ };
31
+
32
+ var rzp1 = new Razorpay(options);
33
+
34
+ // 4. Attach Failure Handler (as per your documentation)
35
+ rzp1.on('payment.failed', function (response){
36
+ window.ReactNativeWebView.postMessage(JSON.stringify({
37
+ type: 'PAYMENT_FAILED',
38
+ error: response.error
39
+ }));
40
+ });
41
+
42
+ // 5. Open Widget
43
+ rzp1.open();
44
+ </script>
45
+ </body>
46
+ </html>
47
+ `,Q=(r)=>{let B=JSON.parse(r.nativeEvent.data);if(B.type==="PAYMENT_SUCCESS")d(B.data);else if(B.type==="PAYMENT_FAILED")g(B.error);else if(B.type==="PAYMENT_CLOSED")_()},P=(r)=>{let{url:B}=r;if(!B.startsWith("http")&&!B.startsWith("https")&&!B.startsWith("about:blank"))return o.openURL(B).catch((E)=>{console.error("Couldn't open UPI app",E)}),!1;return!0};return K(i,{visible:!0,transparent:!0,animationType:"slide",onRequestClose:_,children:K(S,{style:{...I.absoluteFillObject,zIndex:1000,backgroundColor:"rgba(0,0,0,0.5)"},children:K(G.default,{originWhitelist:["*","http://*","https://*","upi://*","tez://*","phonepe://*"],source:{html:Y},onMessage:Q,onShouldStartLoadWithRequest:P,javaScriptEnabled:!0,style:{flex:1,backgroundColor:"transparent"},startInLoadingState:!0,renderLoading:()=>K(S,{style:{flex:1,justifyContent:"center",alignItems:"center",backgroundColor:"transparent",zIndex:1001,...I.absoluteFillObject},children:K(n,{size:"large",color:f.theme?.color||"#3399cc"},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)};import{jsxDEV as W}from"react/jsx-dev-runtime";var v=t(void 0),Yf=({children:f})=>{let[d,g]=L(!1),[_,T]=L(null),[M,X]=L(null),Y=(P,r)=>{T(P),X(r),g(!0)},Q=()=>{if(g(!1),M?.onClose)M.onClose();X(null)};return W(v.Provider,{value:{openCheckout:Y,closeCheckout:Q},children:[f,d&&_&&M&&W(R,{options:_,onSuccess:(P)=>{M.onSuccess(P),g(!1)},onFailure:(P)=>{M.onFailure(P.error),g(!1)},onClose:()=>{Q()}},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},Zf=()=>{let f=c(v);if(!f)throw Error("useRazorpay must be used within a RazorpayProvider");return f};export{Zf as useRazorpay,Yf as RazorpayProvider,R as RazorpayCheckout};
48
+
49
+ //# debugId=74A338E7CE466FDB64756E2164756E21
@@ -0,0 +1,15 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["..\\node_modules\\@babel\\runtime\\helpers\\interopRequireDefault.js", "..\\node_modules\\react-native-webview\\lib\\WebView.styles.js", "..\\node_modules\\react-native-webview\\lib\\WebView.js", "..\\src\\components\\provider.tsx", "..\\src\\components\\razorpayCheckout.tsx", "..\\node_modules\\react-native-webview\\index.js"],
4
+ "sourcesContent": [
5
+ "function _interopRequireDefault(e) {\n return e && e.__esModule ? e : {\n \"default\": e\n };\n}\nmodule.exports = _interopRequireDefault, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;",
6
+ "Object.defineProperty(exports,\"__esModule\",{value:true});exports.default=void 0;var _reactNative=require(\"react-native\");var styles=_reactNative.StyleSheet.create({container:{flex:1,overflow:'hidden'},loadingOrErrorView:{position:'absolute',flex:1,justifyContent:'center',alignItems:'center',height:'100%',width:'100%',backgroundColor:'white'},loadingProgressBar:{height:20},errorText:{fontSize:14,textAlign:'center',marginBottom:2},errorTextTitle:{fontSize:15,fontWeight:'500',marginBottom:10},webView:{backgroundColor:'#ffffff'},flexStart:{alignSelf:'flex-start'},colorRed:{color:'red'}});var _default=exports.default=styles;",
7
+ "var _interopRequireDefault=require(\"@babel/runtime/helpers/interopRequireDefault\");Object.defineProperty(exports,\"__esModule\",{value:true});exports.default=exports.WebView=void 0;var _react=_interopRequireDefault(require(\"react\"));var _reactNative=require(\"react-native\");var _WebView=_interopRequireDefault(require(\"./WebView.styles\"));var _jsxRuntime=require(\"react/jsx-runtime\");var _this=this,_jsxFileName=\"/home/circleci/code/src/WebView.tsx\";var WebView=exports.WebView=function WebView(){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:_WebView.default.flexStart,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:_WebView.default.colorRed,children:\"React Native WebView does not support this platform.\"})});};var _default=exports.default=WebView;",
8
+ "import React, { createContext, useContext, useState, ReactNode } from \"react\";\r\nimport { RazorpayCheckout } from \"./razorpayCheckout\"; // The component we made earlier\r\nimport {\r\n RazorpayOptions,\r\n RazorpaySuccessResponse,\r\n RazorpayErrorResponse,\r\n} from \"../types\";\r\n\r\n// Define the shape of our callbacks\r\ninterface CheckoutCallbacks {\r\n onSuccess: (data: RazorpaySuccessResponse) => void;\r\n onFailure: (error: RazorpayErrorResponse[\"error\"]) => void;\r\n onClose?: () => void;\r\n}\r\n\r\ninterface RazorpayContextType {\r\n openCheckout: (\r\n options: RazorpayOptions,\r\n callbacks: CheckoutCallbacks,\r\n ) => void;\r\n closeCheckout: () => void;\r\n}\r\n\r\nconst RazorpayContext = createContext<RazorpayContextType | undefined>(\r\n undefined,\r\n);\r\n\r\nexport const RazorpayProvider = ({ children }: { children: ReactNode }) => {\r\n const [isVisible, setIsVisible] = useState(false);\r\n const [checkoutOptions, setCheckoutOptions] =\r\n useState<RazorpayOptions | null>(null);\r\n const [callbacks, setCallbacks] = useState<CheckoutCallbacks | null>(null);\r\n\r\n const openCheckout = (options: RazorpayOptions, cbs: CheckoutCallbacks) => {\r\n setCheckoutOptions(options);\r\n setCallbacks(cbs);\r\n setIsVisible(true);\r\n };\r\n\r\n const closeCheckout = () => {\r\n setIsVisible(false);\r\n // Optional: Clear options after a delay if needed\r\n if (callbacks?.onClose) {\r\n callbacks.onClose();\r\n }\r\n setCallbacks(null);\r\n };\r\n\r\n return (\r\n <RazorpayContext.Provider value={{ openCheckout, closeCheckout }}>\r\n {children}\r\n\r\n {/* The Global Payment Overlay */}\r\n {isVisible && checkoutOptions && callbacks && (\r\n <RazorpayCheckout\r\n options={checkoutOptions}\r\n onSuccess={(data) => {\r\n callbacks.onSuccess(data);\r\n setIsVisible(false); // Auto close on success\r\n }}\r\n onFailure={(error) => {\r\n callbacks.onFailure(error.error);\r\n setIsVisible(false); // Auto close on failure\r\n }}\r\n onClose={() => {\r\n closeCheckout();\r\n }}\r\n />\r\n )}\r\n </RazorpayContext.Provider>\r\n );\r\n};\r\n\r\n// The Hook\r\nexport const useRazorpay = () => {\r\n const context = useContext(RazorpayContext);\r\n if (!context) {\r\n throw new Error(\"useRazorpay must be used within a RazorpayProvider\");\r\n }\r\n return context;\r\n};\r\n",
9
+ "import React from \"react\";\r\nimport {\r\n StyleSheet,\r\n View,\r\n ActivityIndicator,\r\n Linking,\r\n Modal,\r\n} from \"react-native\";\r\nimport { WebView } from \"react-native-webview\";\r\nimport {\r\n RazorpayErrorResponse,\r\n RazorpayOptions,\r\n RazorpaySuccessResponse,\r\n} from \"../types\";\r\n\r\ninterface RazorpayCheckoutProps {\r\n options: RazorpayOptions; // The exact options object you listed in your prompt\r\n onSuccess: (data: RazorpaySuccessResponse) => void;\r\n onFailure: (error: RazorpayErrorResponse) => void;\r\n onClose: () => void;\r\n}\r\n\r\nconst RazorpayCheckout = ({\r\n options,\r\n onSuccess,\r\n onFailure,\r\n onClose,\r\n}: RazorpayCheckoutProps) => {\r\n // We inject your specific options into the HTML\r\n // We remove 'handler' from your options because functions can't be passed to WebView\r\n // We will re-attach our own handler inside the HTML\r\n const { handler, ...optionsWithoutHandler } = options;\r\n const optionsString = JSON.stringify(optionsWithoutHandler);\r\n\r\n const htmlContent = `\r\n <html>\r\n <head>\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <style>\r\n body { display: flex; justify-content: center; align-items: center; background-color: transparent; }\r\n </style>\r\n </head>\r\n <body>\r\n <script src=\"https://checkout.razorpay.com/v1/checkout.js\"></script>\r\n <script>\r\n // 1. Parse the options passed from React Native\r\n var options = ${optionsString};\r\n\r\n // 2. Attach the Success Handler\r\n options.handler = function (response){\r\n window.ReactNativeWebView.postMessage(JSON.stringify({\r\n type: 'PAYMENT_SUCCESS',\r\n data: response\r\n }));\r\n };\r\n\r\n // 3. Attach Modal Dismiss (User closed the popup)\r\n options.modal = {\r\n ondismiss: function(){\r\n window.ReactNativeWebView.postMessage(JSON.stringify({\r\n type: 'PAYMENT_CLOSED'\r\n }));\r\n }\r\n };\r\n\r\n var rzp1 = new Razorpay(options);\r\n\r\n // 4. Attach Failure Handler (as per your documentation)\r\n rzp1.on('payment.failed', function (response){\r\n window.ReactNativeWebView.postMessage(JSON.stringify({\r\n type: 'PAYMENT_FAILED',\r\n error: response.error\r\n }));\r\n });\r\n\r\n // 5. Open Widget\r\n rzp1.open();\r\n </script> \r\n </body>\r\n </html>\r\n `;\r\n\r\n const handleMessage = (event: any) => {\r\n const message = JSON.parse(event.nativeEvent.data);\r\n\r\n if (message.type === \"PAYMENT_SUCCESS\") {\r\n onSuccess(message.data);\r\n } else if (message.type === \"PAYMENT_FAILED\") {\r\n onFailure(message.error);\r\n } else if (message.type === \"PAYMENT_CLOSED\") {\r\n onClose();\r\n }\r\n };\r\n\r\n const handleNavigation = (request: any) => {\r\n const { url } = request;\r\n\r\n // Handle UPI Deep Linking (GPay, PhonePe, Paytm, etc.)\r\n // If the URL is not http/https, it's likely a scheme for another app\r\n if (\r\n !url.startsWith(\"http\") &&\r\n !url.startsWith(\"https\") &&\r\n !url.startsWith(\"about:blank\")\r\n ) {\r\n Linking.openURL(url).catch((err) => {\r\n console.error(\"Couldn't open UPI app\", err);\r\n });\r\n return false; // Stop WebView from trying to load it\r\n }\r\n return true; // Allow normal loading\r\n };\r\n\r\n return (\r\n <Modal\r\n visible={true}\r\n transparent={true}\r\n animationType=\"slide\" // Slide up effect like a native sheet\r\n onRequestClose={onClose}\r\n >\r\n <View\r\n style={{\r\n ...StyleSheet.absoluteFillObject,\r\n zIndex: 1000,\r\n backgroundColor: \"rgba(0,0,0,0.5)\",\r\n }}\r\n >\r\n <WebView\r\n originWhitelist={[\r\n \"*\",\r\n \"http://*\",\r\n \"https://*\",\r\n \"upi://*\",\r\n \"tez://*\",\r\n \"phonepe://*\",\r\n ]}\r\n source={{ html: htmlContent }}\r\n onMessage={handleMessage}\r\n onShouldStartLoadWithRequest={handleNavigation}\r\n javaScriptEnabled={true}\r\n style={{ flex: 1, backgroundColor: \"transparent\" }}\r\n startInLoadingState={true}\r\n renderLoading={() => (\r\n <View\r\n style={{\r\n flex: 1,\r\n justifyContent: \"center\",\r\n alignItems: \"center\",\r\n backgroundColor: \"transparent\",\r\n zIndex: 1001,\r\n ...StyleSheet.absoluteFillObject,\r\n }}\r\n >\r\n <ActivityIndicator\r\n size=\"large\"\r\n color={options.theme?.color || \"#3399cc\"}\r\n />\r\n </View>\r\n )}\r\n />\r\n </View>\r\n </Modal>\r\n );\r\n};\r\n\r\nexport { RazorpayCheckout };\r\n",
10
+ "import WebView from './lib/WebView';\n\nexport { WebView };\nexport default WebView;\n"
11
+ ],
12
+ "mappings": "goBAAA,SAAS,CAAsB,CAAC,EAAG,CACjC,OAAO,GAAK,EAAE,WAAa,EAAI,CAC7B,QAAW,CACb,EAEF,EAAO,QAAU,EAAwB,EAAO,QAAQ,WAAa,GAAM,EAAO,QAAQ,QAAa,EAAO,wBCL9G,OAAO,eAAe,EAAQ,aAAa,CAAC,MAAM,EAAI,CAAC,EAAU,UAAa,OAAE,IAAI,oBAAyC,EAAO,EAAa,WAAW,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,mBAAmB,CAAC,SAAS,WAAW,KAAK,EAAE,eAAe,SAAS,WAAW,SAAS,OAAO,OAAO,MAAM,OAAO,gBAAgB,OAAO,EAAE,mBAAmB,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,SAAS,GAAG,UAAU,SAAS,aAAa,CAAC,EAAE,eAAe,CAAC,SAAS,GAAG,WAAW,MAAM,aAAa,EAAE,EAAE,QAAQ,CAAC,gBAAgB,SAAS,EAAE,UAAU,CAAC,UAAU,YAAY,EAAE,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,EAAM,EAAiB,UAAQ,ICA/Y,wBAA4I,kDAAzW,IAAI,MAA+E,OAAO,eAAe,EAAQ,aAAa,CAAC,MAAM,EAAI,CAAC,EAAU,UAAgB,UAAa,OAAE,IAAI,GAAO,EAA+B,CAAQ,EAAM,oBAAyC,EAAS,KAAkD,EAAqH,EAAQ,EAAQ,QAAQ,QAAgB,EAAE,CAAC,OAAqB,MAAK,EAAa,KAAK,CAAC,MAAM,EAAS,QAAQ,UAAU,SAAwB,MAAK,EAAa,KAAK,CAAC,MAAM,EAAS,QAAQ,SAAS,SAAS,sDAAsD,CAAC,CAAC,CAAC,GAAQ,GAAS,EAAQ,QAAQ,ICAhvB,wBAAgB,gBAAe,cAAY,cCC3C,qBACE,UACA,uBACA,aACA,WACA,qBCNF,8DDsBA,IAAM,EAAmB,EACvB,UACA,YACA,YACA,aAC2B,CAI3B,IAAQ,aAAY,GAA0B,EAGxC,EAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAFE,KAAK,UAAU,CAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkDpD,EAAgB,CAAC,IAAe,CACpC,IAAM,EAAU,KAAK,MAAM,EAAM,YAAY,IAAI,EAEjD,GAAI,EAAQ,OAAS,kBACnB,EAAU,EAAQ,IAAI,EACjB,QAAI,EAAQ,OAAS,iBAC1B,EAAU,EAAQ,KAAK,EAClB,QAAI,EAAQ,OAAS,iBAC1B,EAAQ,GAIN,EAAmB,CAAC,IAAiB,CACzC,IAAQ,OAAQ,EAIhB,GACE,CAAC,EAAI,WAAW,MAAM,GACtB,CAAC,EAAI,WAAW,OAAO,GACvB,CAAC,EAAI,WAAW,aAAa,EAK7B,OAHA,EAAQ,QAAQ,CAAG,EAAE,MAAM,CAAC,IAAQ,CAClC,QAAQ,MAAM,wBAAyB,CAAG,EAC3C,EACM,GAET,MAAO,IAGT,OACE,EA+CE,EA/CF,CACE,QAAS,GACT,YAAa,GACb,cAAc,QACd,eAAgB,EAJlB,SAME,EAwCE,EAxCF,CACE,MAAO,IACF,EAAW,mBACd,OAAQ,KACR,gBAAiB,iBACnB,EALF,SAOE,EAAC,UAAD,CACE,gBAAiB,CACf,IACA,WACA,YACA,UACA,UACA,aACF,EACA,OAAQ,CAAE,KAAM,CAAY,EAC5B,UAAW,EACX,6BAA8B,EAC9B,kBAAmB,GACnB,MAAO,CAAE,KAAM,EAAG,gBAAiB,aAAc,EACjD,oBAAqB,GACrB,cAAe,IACb,EAcE,EAdF,CACE,MAAO,CACL,KAAM,EACN,eAAgB,SAChB,WAAY,SACZ,gBAAiB,cACjB,OAAQ,QACL,EAAW,kBAChB,EARF,SAUE,EAAC,EAAD,CACE,KAAK,QACL,MAAO,EAAQ,OAAO,OAAS,WAFjC,qBAGA,GAbF,qBAcE,GA9BN,qBAgCA,GAvCF,qBAwCE,GA9CJ,qBA+CE,kDDzIN,IAAM,EAAkB,EACtB,MACF,EAEa,GAAmB,EAAG,cAAwC,CACzE,IAAO,EAAW,GAAgB,EAAS,EAAK,GACzC,EAAiB,GACtB,EAAiC,IAAI,GAChC,EAAW,GAAgB,EAAmC,IAAI,EAEnE,EAAe,CAAC,EAA0B,IAA2B,CACzE,EAAmB,CAAO,EAC1B,EAAa,CAAG,EAChB,EAAa,EAAI,GAGb,EAAgB,IAAM,CAG1B,GAFA,EAAa,EAAK,EAEd,GAAW,QACb,EAAU,QAAQ,EAEpB,EAAa,IAAI,GAGnB,OACE,EAoBE,EAAgB,SApBlB,CAA0B,MAAO,CAAE,eAAc,eAAc,EAA/D,SAoBE,CAnBC,EAGA,GAAa,GAAmB,GAC/B,EAAC,EAAD,CACE,QAAS,EACT,UAAW,CAAC,IAAS,CACnB,EAAU,UAAU,CAAI,EACxB,EAAa,EAAK,GAEpB,UAAW,CAAC,IAAU,CACpB,EAAU,UAAU,EAAM,KAAK,EAC/B,EAAa,EAAK,GAEpB,QAAS,IAAM,CACb,EAAc,IAXlB,qBAaA,IAlBJ,qBAoBE,GAKO,GAAc,IAAM,CAC/B,IAAM,EAAU,EAAW,CAAe,EAC1C,GAAI,CAAC,EACH,MAAU,MAAM,oDAAoD,EAEtE,OAAO",
13
+ "debugId": "74A338E7CE466FDB64756E2164756E21",
14
+ "names": []
15
+ }
@@ -0,0 +1,133 @@
1
+ export interface RazorpaySuccessResponse {
2
+ razorpay_payment_id: string;
3
+ razorpay_order_id: string;
4
+ razorpay_signature: string;
5
+ }
6
+ export interface RazorpayErrorResponse {
7
+ error: {
8
+ code: string;
9
+ description: string;
10
+ source: string;
11
+ step: string;
12
+ reason: string;
13
+ metadata: {
14
+ order_id: string;
15
+ payment_id: string;
16
+ };
17
+ };
18
+ }
19
+ export interface RazorpayTheme {
20
+ /** Thematic color to modify the appearance of Checkout (e.g., "#3399cc") */
21
+ color?: string;
22
+ /** Link to a backdrop image */
23
+ backdrop_color?: string;
24
+ /** Hides the top bar */
25
+ hide_topbar?: boolean;
26
+ }
27
+ export interface RazorpayPrefill {
28
+ /** Cardholder or user name */
29
+ name?: string;
30
+ /** User email */
31
+ email?: string;
32
+ /** User phone number in format +(country code)(phone number) */
33
+ contact?: string;
34
+ /** Auto-select method (e.g., "card", "netbanking", "wallet", "emi", "upi") */
35
+ method?: string;
36
+ }
37
+ export interface RazorpayModal {
38
+ /** Function called when the user closes the checkout modal */
39
+ ondismiss?: () => void;
40
+ /** Keep the modal open after payment failure */
41
+ confirm_close?: boolean;
42
+ /** Custom animation for modal */
43
+ animation?: boolean;
44
+ }
45
+ export interface RazorpayRetry {
46
+ /** Enable or disable retries */
47
+ enabled: boolean;
48
+ /** Maximum number of retries allowed */
49
+ max_count?: number;
50
+ }
51
+ export interface RazorpayReadOnly {
52
+ email?: boolean;
53
+ contact?: boolean;
54
+ name?: boolean;
55
+ }
56
+ export interface RazorpayHidden {
57
+ email?: boolean;
58
+ contact?: boolean;
59
+ name?: boolean;
60
+ }
61
+ export interface RazorpayConfig {
62
+ display?: {
63
+ blocks?: any;
64
+ sequence?: string[];
65
+ preferences?: any;
66
+ language?: "en" | "hi" | "gu" | "mr" | "bn" | "ta" | "te";
67
+ };
68
+ }
69
+ export interface RazorpayOptions {
70
+ /** API Key ID generated from the Dashboard */
71
+ key: string;
72
+ /** Payment amount in the smallest currency subunit (e.g., 50000 for ₹500.00) */
73
+ amount: number | string;
74
+ /** The currency code (e.g., "INR") */
75
+ currency: string;
76
+ /** Your Business/Enterprise name shown on the Checkout form */
77
+ name: string;
78
+ /** Description of the purchase item shown on the Checkout form */
79
+ description?: string;
80
+ /** Link to an image (usually your business logo) or base64 string */
81
+ image?: string;
82
+ /** Order ID generated via Orders API (Required for standard payments) */
83
+ order_id?: string;
84
+ /** Subscription ID (Required for recurring payments) */
85
+ subscription_id?: string;
86
+ /** Handler function for successful payment */
87
+ handler?: (response: RazorpaySuccessResponse) => void;
88
+ /** Object to prefill customer contact information */
89
+ prefill?: RazorpayPrefill;
90
+ /** Set of key-value pairs (max 15) for additional info */
91
+ notes?: Record<string, string>;
92
+ /** Thematic options to modify the appearance */
93
+ theme?: RazorpayTheme;
94
+ /** Modal options */
95
+ modal?: RazorpayModal;
96
+ /** URL to redirect customers to on successful payment */
97
+ callback_url?: string;
98
+ /** Whether to redirect to callback_url (true) or use handler (false) */
99
+ redirect?: boolean;
100
+ /** Unique identifier of customer (for saved cards) */
101
+ customer_id?: string;
102
+ /** Whether to allow saving cards (default: false) */
103
+ remember_customer?: boolean;
104
+ /** Timeout in seconds */
105
+ timeout?: number;
106
+ /** Marks specific fields as read-only */
107
+ readonly?: RazorpayReadOnly;
108
+ /** Hides specific contact details */
109
+ hidden?: RazorpayHidden;
110
+ /** Auto-read OTP for cards/netbanking (Android only) */
111
+ send_sms_hash?: boolean;
112
+ /** Allow rotation of payment page (Android only) */
113
+ allow_rotation?: boolean;
114
+ /** Retry configuration */
115
+ retry?: RazorpayRetry;
116
+ /** Advanced configuration options */
117
+ config?: RazorpayConfig;
118
+ /** Permit customer from changing linked card in subscription */
119
+ subscription_card_change?: boolean;
120
+ /** Accepting recurring payments via emandate/NACH */
121
+ recurring?: boolean;
122
+ }
123
+ export type RazorpayMessage = {
124
+ type: "READY";
125
+ } | {
126
+ type: "SUCCESS";
127
+ payload: RazorpaySuccessResponse;
128
+ } | {
129
+ type: "FAILED";
130
+ payload: RazorpayErrorResponse;
131
+ } | {
132
+ type: "DISMISSED";
133
+ };
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "razorpay-expo",
3
+ "type": "module",
4
+ "version": "1.0.0",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "license": "MIT",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "bun ./builder.ts && bun run generate-types",
17
+ "prepublishOnly": "bun run build",
18
+ "generate-types": "bunx tsc --emitDeclarationOnly --declaration --outDir dist",
19
+ "clear": "rm -rf dist"
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "homepage": "https://github.com/meabhisingh/razorpay-expo.git#readme",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/meabhisingh/razorpay-expo.git"
31
+ },
32
+ "bugs": "https://github.com/meabhisingh/razorpay-expo/issues",
33
+ "author": "Abhishek Singh <official.6packprogrammer@gmail.com>",
34
+ "devDependencies": {
35
+ "@types/bun": "^1.2.20",
36
+ "tslib": "^2.8.1",
37
+ "typedoc": "^0.28.10"
38
+ },
39
+ "peerDependencies": {
40
+ "react": "^19.2.4",
41
+ "react-dom": "^19.2.4",
42
+ "react-native": "^0.83.1",
43
+ "typescript": "^5"
44
+ },
45
+ "dependencies": {
46
+ "react-native-webview": "^13.16.0"
47
+ }
48
+ }