@jimrising/easymerchantsdk-react-native 1.8.2 → 1.8.5

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.
Files changed (91) hide show
  1. package/.idea/caches/deviceStreaming.xml +22 -0
  2. package/README.md +1014 -257
  3. package/android/build/.transforms/15b6a8a60a6b32d0dcaf609723cf365b/transformed/classes/classes_dex/classes.dex +0 -0
  4. package/android/build/.transforms/8508f1428f740032c45a43f48b1bbe1e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1$1.dex +0 -0
  5. package/android/build/.transforms/8508f1428f740032c45a43f48b1bbe1e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
  6. package/android/build/.transforms/8508f1428f740032c45a43f48b1bbe1e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$2.dex +0 -0
  7. package/android/build/.transforms/8508f1428f740032c45a43f48b1bbe1e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
  8. package/android/build/.transforms/8508f1428f740032c45a43f48b1bbe1e/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
  9. package/android/build/.transforms/eef2d06269ef2e204b4f065513034fca/transformed/classes/classes_dex/classes.dex +0 -0
  10. package/android/build/.transforms/ffabb40f9809b32eb9546ce76fc51764/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule$1$1.dex +0 -0
  11. package/android/build/.transforms/ffabb40f9809b32eb9546ce76fc51764/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
  12. package/android/build/.transforms/ffabb40f9809b32eb9546ce76fc51764/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule$2.dex +0 -0
  13. package/android/build/.transforms/ffabb40f9809b32eb9546ce76fc51764/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
  14. package/android/build/.transforms/ffabb40f9809b32eb9546ce76fc51764/transformed/bundleLibRuntimeToDirRelease/desugar_graph.bin +0 -0
  15. package/android/build/intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar +0 -0
  16. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  17. package/android/build/intermediates/compile_library_classes_jar/release/bundleLibCompileToJarRelease/classes.jar +0 -0
  18. package/android/build/intermediates/full_jar/release/createFullJarRelease/full.jar +0 -0
  19. package/android/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-dependencies.xml +4 -4
  20. package/android/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-libraries.xml +4 -4
  21. package/android/build/intermediates/incremental/release/mergeReleaseResources/compile-file-map.properties +126 -21
  22. package/android/build/intermediates/incremental/release/mergeReleaseResources/merger.xml +3 -3
  23. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
  24. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
  25. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
  26. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
  27. package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
  28. package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
  29. package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
  30. package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
  31. package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/maven.google/androidx/core/group-index.xml +4 -4
  32. package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/maven.google/androidx/lifecycle/group-index.xml +2 -2
  33. package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/maven.google/com/android/tools/build/group-index.xml +14 -14
  34. package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/sdk_index/snapshot.gz +0 -0
  35. package/android/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-dependencies.xml +4 -4
  36. package/android/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-libraries.xml +4 -4
  37. package/android/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-dependencies.xml +4 -4
  38. package/android/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-libraries.xml +4 -4
  39. package/android/build/intermediates/local_aar_for_lint/release/out.aar +0 -0
  40. package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_card_addition_ifo.xml +4 -5
  41. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/multi-v2/values-night-v8.json +2 -2
  42. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/multi-v2/values.json +38 -38
  43. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable.json +62 -62
  44. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/font.json +9 -9
  45. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout.json +20 -20
  46. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-anydpi-v26.json +2 -2
  47. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-hdpi-v4.json +2 -2
  48. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-mdpi-v4.json +2 -2
  49. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-xhdpi-v4.json +2 -2
  50. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-xxhdpi-v4.json +2 -2
  51. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-xxxhdpi-v4.json +2 -2
  52. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/xml.json +2 -2
  53. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
  54. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
  55. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
  56. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
  57. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
  58. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
  59. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
  60. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
  61. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  62. package/android/build/intermediates/runtime_library_classes_jar/release/bundleLibRuntimeToJarRelease/classes.jar +0 -0
  63. package/android/build/intermediates/source_set_path_map/release/mapReleaseSourceSetPaths/file-map.txt +2 -2
  64. package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_card_addition_ifo.xml.flat +0 -0
  65. package/android/build/outputs/aar/jimrising_easymerchantsdk-react-native-release.aar +0 -0
  66. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$1$1.class.uniqueId1 +0 -0
  67. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$1.class.uniqueId0 +0 -0
  68. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$2.class.uniqueId3 +0 -0
  69. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule.class.uniqueId2 +0 -0
  70. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  71. package/android/build/tmp/compileReleaseJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$1$1.class.uniqueId1 +0 -0
  72. package/android/build/tmp/compileReleaseJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$1.class.uniqueId3 +0 -0
  73. package/android/build/tmp/compileReleaseJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$2.class.uniqueId0 +0 -0
  74. package/android/build/tmp/compileReleaseJavaWithJavac/compileTransaction/stash-dir/{RNEasymerchantsdkModule.class.uniqueId1 → RNEasymerchantsdkModule.class.uniqueId2} +0 -0
  75. package/android/build/tmp/compileReleaseJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkPackage.class.uniqueId4 +0 -0
  76. package/android/build/tmp/compileReleaseJavaWithJavac/previous-compilation-data.bin +0 -0
  77. package/android/build.gradle +1 -1
  78. package/android/src/main/java/com/reactlibrary/RNEasymerchantsdkModule.java +77 -38
  79. package/ios/Classes/EasyMerchantSdk.m +0 -1
  80. package/ios/Classes/EasyPayViewController.swift +8 -20
  81. package/ios/Models/Request.swift +181 -1
  82. package/ios/Pods/UserDefaults/UserStoreSingleton.swift +40 -11
  83. package/ios/Pods/ViewControllers/AdditionalInfoVC.swift +7 -2
  84. package/ios/Pods/ViewControllers/BillingInfoVC/BillingInfoVC.swift +20 -10
  85. package/ios/Pods/ViewControllers/OTPVerificationVC.swift +9 -3
  86. package/ios/Pods/ViewControllers/PaymentInformation/PaymentInfoVC.swift +47 -25
  87. package/ios/Pods/ViewControllers/ThreeDSecurePaymentDoneVC.swift +4 -3
  88. package/ios/easymerchantsdk.podspec +1 -1
  89. package/package.json +1 -1
  90. package/android/build/tmp/compileReleaseJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$1.class.uniqueId2 +0 -0
  91. /package/android/build/tmp/{compileReleaseJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkPackage.class.uniqueId3 → compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkPackage.class.uniqueId4} +0 -0
package/README.md CHANGED
@@ -7,7 +7,7 @@ To add the path of sdk in your project. Open your `package.json` file and inside
7
7
 
8
8
  ```json
9
9
  "dependencies": {
10
- "@jimrising/easymerchantsdk-react-native": "^1.8.2"
10
+ "@jimrising/easymerchantsdk-react-native": "^1.8.5"
11
11
  },
12
12
  ```
13
13
 
@@ -128,47 +128,312 @@ import {
128
128
  ScrollView,
129
129
  Platform,
130
130
  NativeModules,
131
+ Switch,
132
+ TouchableOpacity,
133
+ NativeEventEmitter,
131
134
  } from 'react-native';
132
135
 
133
136
  const { RNEasymerchantsdk, EasyMerchantSdk } = NativeModules;
134
137
 
138
+ const externalConfig = {
139
+ amount: '',
140
+ email: '',
141
+ isRecurring: false,
142
+ isAuthenticatedACH: false,
143
+ isSecureAuthentication: false,
144
+ isBillingVisible: false,
145
+ isAdditionalVisible: false,
146
+ emailEditable: true,
147
+ isEmail: true,
148
+ billingInfo: {
149
+ visibility: { billing: false, additional: false },
150
+ billing: {
151
+ address: 'San Fran, Punjab',
152
+ country: 'USA',
153
+ state: 'California',
154
+ city: 'Paris',
155
+ postal_code: '234234',
156
+ },
157
+ billingRequired: {
158
+ address: true,
159
+ country: true,
160
+ state: true,
161
+ city: false,
162
+ postal_code: true,
163
+ },
164
+ additional: {
165
+ name: 'Test User',
166
+ email_address: 'test@gmail.com',
167
+ phone_number: '21408713290',
168
+ description: 'Test',
169
+ },
170
+ additionalRequired: {
171
+ name: true,
172
+ email_address: true,
173
+ phone_number: true,
174
+ description: false,
175
+ },
176
+ },
177
+ themeConfiguration: {
178
+ bodyBackgroundColor: '#0f1715',
179
+ containerBackgroundColor: '#152321',
180
+ primaryFontColor: '#FFFFFF',
181
+ secondaryFontColor: '#A0B5A4',
182
+ primaryButtonBackgroundColor: '#10B981',
183
+ primaryButtonHoverColor: '#059669',
184
+ primaryButtonFontColor: '#FFFFFF',
185
+ secondaryButtonBackgroundColor: '#374151',
186
+ secondaryButtonHoverColor: '#4B5563',
187
+ secondaryButtonFontColor: '#E5E7EB',
188
+ borderRadius: '8',
189
+ fontSize: '14',
190
+ fontWeight: 500,
191
+ fontFamily: '"Inter", sans-serif',
192
+ },
193
+ grailPayParams: {
194
+ role: 'business',
195
+ timeout: 10,
196
+ isSandbox: true,
197
+ brandingName: 'Lyfecycle Payments',
198
+ finderSubtitle: 'Search for your bank',
199
+ searchPlaceholder: 'Enter bank name',
200
+ },
201
+ recurringData: {
202
+ allowCycles: 2,
203
+ intervals: ['weekly', 'monthly'],
204
+ recurringStartType: 'custom',
205
+ recurringStartDate: '07/08/2025',
206
+ },
207
+ androidConfig: {
208
+ currency: 'usd',
209
+ saveCard: true,
210
+ saveAccount: true,
211
+ showReceipt: true,
212
+ showDonate: false,
213
+ showTotal: true,
214
+ showSubmitButton: true,
215
+ paymentMethod: ['card', 'ach'],
216
+ name: 'Pavan',
217
+ fields: {
218
+ visibility: { billing: false, additional: false },
219
+ billing: [
220
+ { name: 'address', required: true, value: 'New Address' },
221
+ { name: 'country', required: true, value: 'India' },
222
+ { name: 'state', required: true, value: 'California' },
223
+ { name: 'city', required: true, value: 'Goa' },
224
+ { name: 'postal_code', required: true, value: '1432456' },
225
+ ],
226
+ additional: [
227
+ { name: 'name', required: true, value: 'Test User 7' },
228
+ { name: 'email_address', required: true, value: 'usertest@gmail.com' },
229
+ { name: 'phone_number', required: true, value: '8978967895' },
230
+ { name: 'description', required: true, value: 'Hi This is description' },
231
+ ],
232
+ },
233
+ appearanceSettings: {
234
+ theme: 'dark',
235
+ bodyBackgroundColor: '#121212',
236
+ containerBackgroundColor: '#1E1E1E',
237
+ primaryFontColor: '#FFFFFF',
238
+ secondaryFontColor: '#B0B0B0',
239
+ primaryButtonBackgroundColor: '#2563EB',
240
+ primaryButtonHoverColor: '#1D4ED8',
241
+ primaryButtonFontColor: '#FFFFFF',
242
+ secondaryButtonBackgroundColor: '#374151',
243
+ secondaryButtonHoverColor: '#4B5563',
244
+ secondaryButtonFontColor: '#E5E7EB',
245
+ borderRadius: '8',
246
+ fontSize: '14',
247
+ fontWeight: '500',
248
+ fontFamily: 'Inter, sans-serif',
249
+ },
250
+ },
251
+ };
252
+
135
253
  const App = () => {
136
- const [amount, setAmount] = useState('');
137
- const [email, setEmail] = useState('');
254
+ const [amount, setAmount] = useState(externalConfig.amount);
255
+ const [email, setEmail] = useState(externalConfig.email);
138
256
  const [environment, setEnvironment] = useState('sandbox');
139
- const [isRecurring, setIsRecurring] = useState(false);
140
- const [emailEditable, setEmailEditable] = useState(true); // Android only
141
- const [isEmail, setIsEmail] = useState(true); // iOS only
257
+ const [isRecurring, setIsRecurring] = useState(externalConfig.isRecurring);
258
+ const [isAuthenticatedACH, setAuthenticatedACH] = useState(externalConfig.isAuthenticatedACH);
259
+ const [isSecureAuthentication, setSecureAuthentication] = useState(externalConfig.isSecureAuthentication);
260
+ const [isBillingVisible, setBillingVisible] = useState(externalConfig.isBillingVisible);
261
+ const [isAdditionalVisible, setAdditionalVisible] = useState(externalConfig.isAdditionalVisible);
262
+ const [emailEditable, setEmailEditable] = useState(externalConfig.emailEditable); // Android
263
+ const [isEmail, setIsEmail] = useState(externalConfig.isEmail); // iOS
264
+ const [billingInfo, setBillingInfo] = useState(externalConfig.billingInfo);
265
+ const [themeConfiguration, setThemeConfiguration] = useState(externalConfig.themeConfiguration);
266
+ const [grailPayParams, setGrailPayParams] = useState(externalConfig.grailPayParams);
267
+ const [recurringData, setRecurringData] = useState(externalConfig.recurringData);
268
+ const [androidConfig, setAndroidConfig] = useState(externalConfig.androidConfig);
142
269
  const [result, setResult] = useState('');
143
270
  const [referenceToken, setReferenceToken] = useState('');
144
271
  const [loading, setLoading] = useState(false);
272
+ const [apiKey, setApiKey] = useState('apiKey');
273
+ const [apiSecret, setApiSecret] = useState('apiSecret');
274
+ const [isEnvironmentLoading, setIsEnvironmentLoading] = useState(false);
275
+
276
+
277
+ const easyMerchantEvents = new NativeEventEmitter(RNEasymerchantsdk);
278
+
279
+ useEffect(() => {
280
+ const successSub = easyMerchantEvents.addListener('PaymentSuccess', (data) => {
281
+ console.log('Payment success event:', data);
282
+ const parsed = JSON.parse(data.response);
283
+ console.log('Parsed PaymentSuccess:', parsed);
284
+
285
+ if (parsed.billingInfo) {
286
+ const billing = JSON.parse(parsed.billingInfo);
287
+ console.log('Billing Info:', billing);
288
+ }
289
+
290
+ if (parsed.additional_info) {
291
+ const additional = JSON.parse(parsed.additional_info);
292
+ console.log('Additional Info:', additional);
293
+ }
294
+
295
+ setResult(JSON.stringify(parsed, null, 2));
296
+ });
297
+
298
+ const statusSub = easyMerchantEvents.addListener('PaymentStatus', (data) => {
299
+ console.log('Raw Payment status event:', data);
300
+ const parsed = JSON.parse(data.statusResponse);
301
+ console.log('Parsed PaymentStatus:', parsed);
302
+
303
+ setResult(JSON.stringify(parsed, null, 2));
304
+ });
305
+
306
+ const statusErrorSub = easyMerchantEvents.addListener('PaymentStatusError', (data) => {
307
+ console.log('Payment status error event:', data);
308
+ setResult(`Status Error: ${JSON.stringify(data)}`);
309
+ });
310
+
311
+ return () => {
312
+ successSub.remove();
313
+ statusSub.remove();
314
+ statusErrorSub.remove();
315
+ };
316
+ }, []);
317
+
318
+
145
319
 
146
320
  useEffect(() => {
147
- const setupIOS = async () => {
148
- if (Platform.OS === 'ios') {
149
- try {
150
- await EasyMerchantSdk.setViewController();
151
-
152
- const iosKey = environment === 'staging'
153
- ? 'stagingApiKey'
154
- : 'sandboxApiKey';
155
-
156
- const iosSecret = environment === 'staging'
157
- ? 'stagingSecretKey'
158
- : 'sandboxSecretKey';
159
-
160
- await EasyMerchantSdk.configureEnvironment(
161
- environment,
162
- iosKey,
163
- iosSecret
164
- );
165
- } catch (err) {
166
- console.error('iOS Initialization Error:', err);
167
- }
168
- }
169
- };
170
- setupIOS();
171
- }, [environment]);
321
+ const updateEnvironment = async () => {
322
+ const key = environment === 'staging'
323
+ ? 'stagingApiKey'
324
+ : 'sandboxApiKey';
325
+ const secret = environment === 'staging'
326
+ ? 'stagingApiSecret'
327
+ : 'sandboxApiSecret';
328
+
329
+ setApiKey(key);
330
+ setApiSecret(secret);
331
+
332
+ if (Platform.OS === 'ios') {
333
+ setIsEnvironmentLoading(true);
334
+ try {
335
+ await EasyMerchantSdk.setViewController();
336
+ await EasyMerchantSdk.configureEnvironment(environment, key, secret);
337
+ console.log(`iOS Environment configured: ${environment} with key ${key}`);
338
+ } catch (err) {
339
+ console.error('iOS Initialization Error:', err);
340
+ Alert.alert('Error', `Failed to configure iOS environment: ${err.message}`);
341
+ } finally {
342
+ setIsEnvironmentLoading(false);
343
+ }
344
+ }
345
+ };
346
+
347
+ updateEnvironment();
348
+ }, [environment]);
349
+
350
+ useEffect(() => {
351
+ setBillingInfo(prev => ({
352
+ ...prev,
353
+ visibility: {
354
+ billing: isBillingVisible,
355
+ additional: isAdditionalVisible,
356
+ },
357
+ }));
358
+ }, [isBillingVisible, isAdditionalVisible]);
359
+
360
+ const updateBillingInfo = (section, field, value) => {
361
+ setBillingInfo(prev => ({
362
+ ...prev,
363
+ [section]: {
364
+ ...prev[section],
365
+ [field]: value,
366
+ },
367
+ }));
368
+ };
369
+
370
+ const updateAndroidConfig = (field, value) => {
371
+ setAndroidConfig(prev => ({
372
+ ...prev,
373
+ [field]: value,
374
+ }));
375
+ };
376
+
377
+ const updateAndroidConfigFields = (section, index, field, value) => {
378
+ setAndroidConfig(prev => ({
379
+ ...prev,
380
+ fields: {
381
+ ...prev.fields,
382
+ [section]: prev.fields[section].map((item, i) =>
383
+ i === index ? { ...item, [field]: value } : item
384
+ ),
385
+ },
386
+ }));
387
+ };
388
+
389
+ const updateAndroidConfigAppearanceSettings = (field, value) => {
390
+ setAndroidConfig(prev => ({
391
+ ...prev,
392
+ appearanceSettings: {
393
+ ...prev.appearanceSettings,
394
+ [field]: value,
395
+ },
396
+ }));
397
+ };
398
+
399
+ const updateThemeConfiguration = (field, value) => {
400
+ setThemeConfiguration(prev => ({
401
+ ...prev,
402
+ [field]: value,
403
+ }));
404
+ };
405
+
406
+ const updateGrailPayParams = (field, value) => {
407
+ setGrailPayParams(prev => ({
408
+ ...prev,
409
+ [field]: value,
410
+ }));
411
+ };
412
+
413
+ const updateRecurringData = (field, value) => {
414
+ setRecurringData(prev => ({
415
+ ...prev,
416
+ [field]: value,
417
+ }));
418
+ };
419
+
420
+ const togglePaymentMethod = (method) => {
421
+ setAndroidConfig(prev => ({
422
+ ...prev,
423
+ paymentMethod: prev.paymentMethod.includes(method)
424
+ ? prev.paymentMethod.filter(m => m !== method)
425
+ : [...prev.paymentMethod, method],
426
+ }));
427
+ };
428
+
429
+ const toggleInterval = (interval) => {
430
+ setRecurringData(prev => ({
431
+ ...prev,
432
+ intervals: prev.intervals.includes(interval)
433
+ ? prev.intervals.filter(i => i !== interval)
434
+ : [...prev.intervals, interval],
435
+ }));
436
+ };
172
437
 
173
438
  const handlePayment = async () => {
174
439
  if (!amount || isNaN(parseFloat(amount)) || parseFloat(amount) <= 0) {
@@ -179,181 +444,98 @@ const App = () => {
179
444
  }
180
445
 
181
446
  setLoading(true);
182
-
183
447
  if (Platform.OS === 'android') {
184
- const config = {
185
- amount,
186
- apiKey: 'apiKey',
187
- secretKey: 'secretKey',
188
- jsonConfig: {
189
- environment,
190
- amount,
191
- tokenOnly: false,
192
- currency: 'usd',
193
- saveCard: true,
194
- saveAccount: true,
195
- authenticatedACH: true,
196
- secureAuthentication: false,
197
- showReceipt: true,
198
- showDonate: false,
199
- showTotal: true,
200
- showSubmitButton: true,
201
- paymentMethod: ['card', 'ach'],
202
- emailEditable,
203
- email,
204
- name: 'Pavan',
205
- fields: {
206
- visibility: { billing: true, additional: false },
207
- billing: [
208
- { name: 'address', required: true, value: 'New Address' },
209
- { name: 'country', required: true, value: 'USA' },
210
- { name: 'state', required: true, value: 'California' },
211
- { name: 'city', required: true, value: 'California' },
212
- { name: 'postal_code', required: true, value: '1432456' },
213
- ],
214
- additional: [
215
- { name: 'name', required: true, value: 'Test User 7' },
216
- { name: 'email_address', required: true, value: 'usertest@gmail.com' },
217
- { name: 'phone_number', required: false, value: '8978967895' },
218
- { name: 'description', required: true, value: 'Hi This is description' },
219
- ],
220
- },
221
- ...(isRecurring && {
222
- recurring: {
223
- enableRecurring: true,
224
- recurringData: {
225
- allowCycles: 2,
226
- intervals: ['Weekly', 'Monthly'],
227
- recurringStartType: 'Custom',
228
- recurringStartDate: '31/12/2026',
229
- },
230
- },
231
- }),
232
- grailPayParams: {
233
- role: 'business',
234
- timeout: 10,
235
- isSandbox: true,
236
- brandingName: 'Lyfecycle Payments',
237
- finderSubtitle: 'Search for your bank',
238
- searchPlaceholder: 'Enter bank name',
239
- },
240
- appearanceSettings: {
241
- theme: 'dark',
242
- bodyBackgroundColor: '#121212',
243
- containerBackgroundColor: '#1E1E1E',
244
- primaryFontColor: '#FFFFFF',
245
- secondaryFontColor: '#B0B0B0',
246
- primaryButtonBackgroundColor: '#2563EB',
247
- primaryButtonHoverColor: '#1D4ED8',
248
- primaryButtonFontColor: '#FFFFFF',
249
- secondaryButtonBackgroundColor: '#374151',
250
- secondaryButtonHoverColor: '#4B5563',
251
- secondaryButtonFontColor: '#E5E7EB',
252
- borderRadius: '8',
253
- fontSize: '14',
254
- fontWeight: '500',
255
- fontFamily: 'Inter, sans-serif'
256
- }
257
- },
258
- };
259
-
260
- try {
261
- const response = await RNEasymerchantsdk.makePayment(config);
262
- console.log('Full payment response:', response);
263
- setResult(JSON.stringify(response, null, 2));
264
- } catch (error) {
265
- setResult(`Error: ${error.message}`);
266
- Alert.alert('Payment Error', error.message);
267
- } finally {
268
- setLoading(false);
269
- }
448
+ await handleAndroidBilling();
270
449
  } else {
271
- handleBilling();
450
+ await handleIosBilling();
272
451
  }
273
452
  };
274
453
 
275
- const handleBilling = async () => {
276
- const billingInfo = {
277
- visibility: { billing: false, additional: false },
278
- billing: {
279
- address: 'San Fran',
280
- country: 'USA',
281
- state: 'California',
282
- city: 'Paris',
283
- postal_code: '234234',
284
- },
285
- billingRequired: {
286
- address: true,
287
- country: true,
288
- state: true,
289
- city: false,
290
- postal_code: true,
291
- },
292
- additional: {
293
- name: 'Test User',
294
- email_address: 'test@gmail.com',
295
- phone_number: '21408713290',
296
- description: 'Test',
297
- },
298
- additionalRequired: {
299
- name: true,
300
- email_address: true,
301
- phone_number: true,
302
- description: false,
454
+ const handleAndroidBilling = async () => {
455
+ const config = {
456
+ amount,
457
+ apiKey,
458
+ secretKey: apiSecret,
459
+ jsonConfig: {
460
+ environment,
461
+ amount,
462
+ tokenOnly: false,
463
+ currency: androidConfig.currency,
464
+ saveCard: androidConfig.saveCard,
465
+ saveAccount: androidConfig.saveAccount,
466
+ authenticatedACH: isAuthenticatedACH,
467
+ secureAuthentication: isSecureAuthentication,
468
+ showReceipt: androidConfig.showReceipt,
469
+ showDonate: androidConfig.showDonate,
470
+ showTotal: androidConfig.showTotal,
471
+ showSubmitButton: androidConfig.showSubmitButton,
472
+ paymentMethod: androidConfig.paymentMethod,
473
+ emailEditable,
474
+ email,
475
+ name: androidConfig.name,
476
+ fields: {
477
+ ...androidConfig.fields,
478
+ visibility: {
479
+ billing: isBillingVisible,
480
+ additional: isAdditionalVisible,
481
+ },
303
482
  },
304
- };
483
+ ...(isRecurring && {
484
+ recurring: {
485
+ enableRecurring: true,
486
+ recurringData,
487
+ },
488
+ }),
489
+ grailPayParams,
490
+ appearanceSettings: androidConfig.appearanceSettings,
491
+ },
492
+ };
305
493
 
306
- const themeConfiguration = {
307
- bodyBackgroundColor: "#121212",
308
- containerBackgroundColor: "#1E1E1E",
309
- primaryFontColor: "#FFFFFF",
310
- secondaryFontColor: "#B0B0B0",
311
- primaryButtonBackgroundColor: "#2563EB",
312
- primaryButtonHoverColor: "#1D4ED8",
313
- primaryButtonFontColor: "#FFFFFF",
314
- secondaryButtonBackgroundColor: "#374151",
315
- secondaryButtonHoverColor: "#4B5563",
316
- secondaryButtonFontColor: "#E5E7EB",
317
- borderRadius: "8",
318
- fontSize: "14",
319
- fontWeight: 500,
320
- fontFamily: "\"Inter\", sans-serif"
321
- };
494
+ try {
495
+ const response = await RNEasymerchantsdk.makePayment(config);
496
+ console.log('Full payment response:', response);
322
497
 
323
- const authConfig = {
324
- role: 'business',
325
- timeout: 10,
326
- isSandbox: true,
327
- brandingName: 'Lyfecycle Payments',
328
- finderSubtitle: 'Search for your bank',
329
- searchPlaceholder: 'Enter bank name',
498
+ const parsedResponse = {
499
+ ...response,
500
+ billingInfo: response.billingInfo ? JSON.parse(response.billingInfo) : null,
501
+ additional_info: response.additional_info ? JSON.parse(response.additional_info) : null,
330
502
  };
331
503
 
504
+ setResult(JSON.stringify(parsedResponse, null, 2));
505
+ } catch (error) {
506
+ setResult(`Error: ${error.message}`);
507
+ Alert.alert('Payment Error', error.message);
508
+ } finally {
509
+ setLoading(false);
510
+ }
511
+ };
512
+
513
+ const handleIosBilling = async () => {
332
514
  try {
333
515
  const result = await EasyMerchantSdk.billing(
334
516
  amount,
335
- 'usd',
517
+ androidConfig.currency || 'usd',
336
518
  billingInfo,
337
- ['card', 'bank'],
519
+ androidConfig.paymentMethod,
338
520
  themeConfiguration,
339
- false, // tokenOnly
340
- true, // saveCard
341
- true, // saveAccount
342
- true, // authenticatedACH
343
- authConfig, // grailPayParams
521
+ false, // tokenOnly
522
+ androidConfig.saveCard,
523
+ androidConfig.saveAccount,
524
+ isAuthenticatedACH,
525
+ grailPayParams,
344
526
  'Submit',
345
- isRecurring, // isRecurring
346
- isRecurring ? 2 : 0, // if isRecurring == true then numOfCycle required
347
- isRecurring ? ['weekly', 'monthly'] : [], // if isRecurring == true then it is required
348
- isRecurring ? 'custom' : '', // if isRecurring == true then it is required
349
- isRecurring ? '07/08/2025' : '', // if isRecurring == true then it is required
350
- true, // secureAuthentication
351
- true, // showReceipt
352
- true, // showTotal
353
- true, // showSubmitButton
527
+ isRecurring,
528
+ isRecurring ? recurringData.allowCycles : 0,
529
+ isRecurring ? recurringData.intervals : [],
530
+ isRecurring ? recurringData.recurringStartType : '',
531
+ isRecurring ? recurringData.recurringStartDate : '',
532
+ isSecureAuthentication,
533
+ androidConfig.showReceipt,
534
+ androidConfig.showTotal,
535
+ androidConfig.showSubmitButton,
354
536
  isEmail,
355
537
  email,
356
- "Pavan"
538
+ androidConfig.name
357
539
  );
358
540
 
359
541
  const refToken = result?.additionalInfo?.threeDSecureStatus?.data?.ref_token;
@@ -361,24 +543,42 @@ const App = () => {
361
543
  setResult(JSON.stringify(result, null, 2));
362
544
  } catch (error) {
363
545
  console.error('Billing Error:', error);
364
- setResult(`❌ Billing Error: ${error.message || JSON.stringify(error)}`);
546
+ setResult(`Billing Error: ${error.message || JSON.stringify(error)}`);
547
+ } finally {
548
+ setLoading(false);
549
+ }
550
+ };
551
+
552
+ const handleCheckStatus = async () => {
553
+ setLoading(true);
554
+ try {
555
+ const response = await RNEasymerchantsdk.checkPaymentStatus();
556
+ console.log('Full payment response:', response);
557
+ setResult(JSON.stringify(response, null, 2));
558
+ } catch (error) {
559
+ setResult(`Error: ${error.message}`);
560
+ Alert.alert('Status Check Error', error.message);
561
+ } finally {
562
+ setLoading(false);
365
563
  }
366
564
  };
367
565
 
368
566
  const handlePaymentReference = async () => {
369
567
  if (Platform.OS === 'android') {
370
- setResult('Payment Reference not supported on Android');
568
+ setResult('Payment Reference not supported on Android');
371
569
  return;
372
570
  }
373
571
  if (!referenceToken) {
374
- setResult('No reference token available from billing');
572
+ setResult('No reference token available');
375
573
  return;
376
574
  }
377
575
  try {
378
- const result = await EasyMerchantSdk.paymentReference(referenceToken);
379
- setResult(`✅ Payment Reference:\n${JSON.stringify(result, null, 2)}`);
576
+ const response = await EasyMerchantSdk.paymentReference(referenceToken);
577
+ setResult(`Payment Reference:\n${JSON.stringify(response, null, 2)}`);
380
578
  } catch (error) {
381
- setResult(`❌ Payment Reference Error: ${error.message || JSON.stringify(error)}`);
579
+ setResult(`Payment Reference Error: ${error.message || JSON.stringify(error)}`);
580
+ } finally {
581
+ setLoading(false);
382
582
  }
383
583
  };
384
584
 
@@ -387,6 +587,8 @@ const App = () => {
387
587
  <ScrollView contentContainerStyle={styles.scrollContent}>
388
588
  <Text style={styles.title}>EasyMerchant SDK</Text>
389
589
 
590
+ <Text style={styles.sectionTitle}>Basic Info</Text>
591
+ <Text style={styles.label}>Amount</Text>
390
592
  <TextInput
391
593
  style={styles.input}
392
594
  placeholder="Enter amount (e.g., 10.00)"
@@ -394,7 +596,7 @@ const App = () => {
394
596
  value={amount}
395
597
  onChangeText={setAmount}
396
598
  />
397
-
599
+ <Text style={styles.label}>Email</Text>
398
600
  <TextInput
399
601
  style={styles.input}
400
602
  placeholder="Enter email"
@@ -403,75 +605,597 @@ const App = () => {
403
605
  onChangeText={setEmail}
404
606
  />
405
607
 
406
- <View style={styles.pickerContainer}>
407
- <Text style={styles.label}>Environment:</Text>
408
- <View style={styles.buttonGroup}>
409
- <Button
410
- title="Sandbox"
411
- onPress={() => setEnvironment('sandbox')}
412
- color={environment === 'sandbox' ? '#2563EB' : '#ccc'}
608
+ <Text style={styles.sectionTitle}>Environment</Text>
609
+ <View style={styles.pickerContainer}>
610
+ <Text style={styles.label}>Select Environment</Text>
611
+ <View style={styles.buttonGroup}>
612
+ <TouchableOpacity
613
+ style={[
614
+ styles.environmentButton,
615
+ { backgroundColor: environment === 'sandbox' ? '#2563EB' : '#ccc' },
616
+ ]}
617
+ onPress={() => {
618
+ console.log('Sandbox tapped, setting environment to sandbox');
619
+ setEnvironment('sandbox');
620
+ }}
621
+ disabled={isEnvironmentLoading || environment === 'sandbox'}
622
+ >
623
+ <Text style={styles.buttonText}>Sandbox</Text>
624
+ </TouchableOpacity>
625
+ <TouchableOpacity
626
+ style={[
627
+ styles.environmentButton,
628
+ { backgroundColor: environment === 'staging' ? '#2563EB' : '#ccc' },
629
+ ]}
630
+ onPress={() => {
631
+ console.log('Staging tapped, setting environment to staging');
632
+ setEnvironment('staging');
633
+ }}
634
+ disabled={isEnvironmentLoading || environment === 'staging'}
635
+ >
636
+ <Text style={styles.buttonText}>Staging</Text>
637
+ </TouchableOpacity>
638
+ </View>
639
+ </View>
640
+
641
+
642
+ <Text style={styles.sectionTitle}>Payment Options</Text>
643
+ <View style={styles.toggleContainer}>
644
+ <Text style={styles.label}>Recurring Payment</Text>
645
+ <Switch
646
+ value={isRecurring}
647
+ onValueChange={setIsRecurring}
648
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
649
+ thumbColor={isRecurring ? '#fff' : '#f4f3f4'}
650
+ />
651
+ </View>
652
+ <View style={styles.toggleContainer}>
653
+ <Text style={styles.label}>Authenticated ACH</Text>
654
+ <Switch
655
+ value={isAuthenticatedACH}
656
+ onValueChange={setAuthenticatedACH}
657
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
658
+ thumbColor={isAuthenticatedACH ? '#fff' : '#f4f3f4'}
659
+ />
660
+ </View>
661
+ <View style={styles.toggleContainer}>
662
+ <Text style={styles.label}>3DS</Text>
663
+ <Switch
664
+ value={isSecureAuthentication}
665
+ onValueChange={setSecureAuthentication}
666
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
667
+ thumbColor={isSecureAuthentication ? '#fff' : '#f4f3f4'}
668
+ />
669
+ </View>
670
+ <View style={styles.toggleContainer}>
671
+ <Text style={styles.label}>Billing Visible</Text>
672
+ <Switch
673
+ value={isBillingVisible}
674
+ onValueChange={setBillingVisible}
675
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
676
+ thumbColor={isBillingVisible ? '#fff' : '#f4f3f4'}
677
+ />
678
+ </View>
679
+ <View style={styles.toggleContainer}>
680
+ <Text style={styles.label}>Additional Info Visible</Text>
681
+ <Switch
682
+ value={isAdditionalVisible}
683
+ onValueChange={setAdditionalVisible}
684
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
685
+ thumbColor={isAdditionalVisible ? '#fff' : '#f4f3f4'}
686
+ />
687
+ </View>
688
+ <Text style={styles.label}>Payment Methods (Shared)</Text>
689
+ <View style={styles.buttonGroup}>
690
+ <Button
691
+ title="Card"
692
+ onPress={() => togglePaymentMethod('card')}
693
+ color={androidConfig.paymentMethod.includes('card') ? '#2563EB' : '#ccc'}
694
+ />
695
+ <Button
696
+ title="ACH"
697
+ onPress={() => togglePaymentMethod('ach')}
698
+ color={androidConfig.paymentMethod.includes('ach') ? '#2563EB' : '#ccc'}
699
+ />
700
+ </View>
701
+ {Platform.OS === 'android' && (
702
+ <View style={styles.toggleContainer}>
703
+ <Text style={styles.label}>Email Editable (Android)</Text>
704
+ <Switch
705
+ value={emailEditable}
706
+ onValueChange={setEmailEditable}
707
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
708
+ thumbColor={emailEditable ? '#fff' : '#f4f3f4'}
413
709
  />
414
- <Button
415
- title="Staging"
416
- onPress={() => setEnvironment('staging')}
417
- color={environment === 'staging' ? '#2563EB' : '#ccc'}
710
+ </View>
711
+ )}
712
+ {Platform.OS === 'ios' && (
713
+ <View style={styles.toggleContainer}>
714
+ <Text style={styles.label}>Allow Email (iOS)</Text>
715
+ <Switch
716
+ value={isEmail}
717
+ onValueChange={setIsEmail}
718
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
719
+ thumbColor={isEmail ? '#fff' : '#f4f3f4'}
418
720
  />
419
721
  </View>
420
- </View>
722
+ )}
421
723
 
422
- <View style={styles.pickerContainer}>
423
- <Text style={styles.label}>Recurring Payment:</Text>
424
- <View style={styles.buttonGroup}>
425
- <Button
426
- title="Yes"
427
- onPress={() => setIsRecurring(true)}
428
- color={isRecurring ? '#2563EB' : '#ccc'}
724
+ <Text style={styles.sectionTitle}>Billing Info</Text>
725
+ <Text style={styles.label}>Billing Address</Text>
726
+ <TextInput
727
+ style={styles.input}
728
+ value={billingInfo.billing.address}
729
+ onChangeText={value => updateBillingInfo('billing', 'address', value)}
730
+ />
731
+ <Text style={styles.label}>Billing Country</Text>
732
+ <TextInput
733
+ style={styles.input}
734
+ value={billingInfo.billing.country}
735
+ onChangeText={value => updateBillingInfo('billing', 'country', value)}
736
+ />
737
+ <Text style={styles.label}>Billing State</Text>
738
+ <TextInput
739
+ style={styles.input}
740
+ value={billingInfo.billing.state}
741
+ onChangeText={value => updateBillingInfo('billing', 'state', value)}
742
+ />
743
+ <Text style={styles.label}>Billing City</Text>
744
+ <TextInput
745
+ style={styles.input}
746
+ value={billingInfo.billing.city}
747
+ onChangeText={value => updateBillingInfo('billing', 'city', value)}
748
+ />
749
+ <Text style={styles.label}>Billing Postal Code</Text>
750
+ <TextInput
751
+ style={styles.input}
752
+ value={billingInfo.billing.postal_code}
753
+ onChangeText={value => updateBillingInfo('billing', 'postal_code', value)}
754
+ />
755
+ <Text style={styles.label}>Billing Required: Address</Text>
756
+ <Switch
757
+ value={billingInfo.billingRequired.address}
758
+ onValueChange={value => updateBillingInfo('billingRequired', 'address', value)}
759
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
760
+ thumbColor={billingInfo.billingRequired.address ? '#fff' : '#f4f3f4'}
761
+ />
762
+ <Text style={styles.label}>Billing Required: Country</Text>
763
+ <Switch
764
+ value={billingInfo.billingRequired.country}
765
+ onValueChange={value => updateBillingInfo('billingRequired', 'country', value)}
766
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
767
+ thumbColor={billingInfo.billingRequired.country ? '#fff' : '#f4f3f4'}
768
+ />
769
+ <Text style={styles.label}>Billing Required: State</Text>
770
+ <Switch
771
+ value={billingInfo.billingRequired.state}
772
+ onValueChange={value => updateBillingInfo('billingRequired', 'state', value)}
773
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
774
+ thumbColor={billingInfo.billingRequired.state ? '#fff' : '#f4f3f4'}
775
+ />
776
+ <Text style={styles.label}>Billing Required: City</Text>
777
+ <Switch
778
+ value={billingInfo.billingRequired.city}
779
+ onValueChange={value => updateBillingInfo('billingRequired', 'city', value)}
780
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
781
+ thumbColor={billingInfo.billingRequired.city ? '#fff' : '#f4f3f4'}
782
+ />
783
+ <Text style={styles.label}>Billing Required: Postal Code</Text>
784
+ <Switch
785
+ value={billingInfo.billingRequired.postal_code}
786
+ onValueChange={value => updateBillingInfo('billingRequired', 'postal_code', value)}
787
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
788
+ thumbColor={billingInfo.billingRequired.postal_code ? '#fff' : '#f4f3f4'}
789
+ />
790
+ <Text style={styles.label}>Additional: Name</Text>
791
+ <TextInput
792
+ style={styles.input}
793
+ value={billingInfo.additional.name}
794
+ onChangeText={value => updateBillingInfo('additional', 'name', value)}
795
+ />
796
+ <Text style={styles.label}>Additional: Email Address</Text>
797
+ <TextInput
798
+ style={styles.input}
799
+ value={billingInfo.additional.email_address}
800
+ onChangeText={value => updateBillingInfo('additional', 'email_address', value)}
801
+ />
802
+ <Text style={styles.label}>Additional: Phone Number</Text>
803
+ <TextInput
804
+ style={styles.input}
805
+ value={billingInfo.additional.phone_number}
806
+ onChangeText={value => updateBillingInfo('additional', 'phone_number', value)}
807
+ />
808
+ <Text style={styles.label}>Additional: Description</Text>
809
+ <TextInput
810
+ style={styles.input}
811
+ value={billingInfo.additional.description}
812
+ onChangeText={value => updateBillingInfo('additional', 'description', value)}
813
+ />
814
+ <Text style={styles.label}>Additional Required: Name</Text>
815
+ <Switch
816
+ value={billingInfo.additionalRequired.name}
817
+ onValueChange={value => updateBillingInfo('additionalRequired', 'name', value)}
818
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
819
+ thumbColor={billingInfo.additionalRequired.name ? '#fff' : '#f4f3f4'}
820
+ />
821
+ <Text style={styles.label}>Additional Required: Email Address</Text>
822
+ <Switch
823
+ value={billingInfo.additionalRequired.email_address}
824
+ onValueChange={value => updateBillingInfo('additionalRequired', 'email_address', value)}
825
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
826
+ thumbColor={billingInfo.additionalRequired.email_address ? '#fff' : '#f4f3f4'}
827
+ />
828
+ <Text style={styles.label}>Additional Required: Phone Number</Text>
829
+ <Switch
830
+ value={billingInfo.additionalRequired.phone_number}
831
+ onValueChange={value => updateBillingInfo('additionalRequired', 'phone_number', value)}
832
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
833
+ thumbColor={billingInfo.additionalRequired.phone_number ? '#fff' : '#f4f3f4'}
834
+ />
835
+ <Text style={styles.label}>Additional Required: Description</Text>
836
+ <Switch
837
+ value={billingInfo.additionalRequired.description}
838
+ onValueChange={value => updateBillingInfo('additionalRequired', 'description', value)}
839
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
840
+ thumbColor={billingInfo.additionalRequired.description ? '#fff' : '#f4f3f4'}
841
+ />
842
+
843
+ {Platform.OS === 'android' && (
844
+ <>
845
+ <Text style={styles.sectionTitle}>Android Configuration</Text>
846
+ <Text style={styles.label}>Currency</Text>
847
+ <TextInput
848
+ style={styles.input}
849
+ value={androidConfig.currency}
850
+ onChangeText={value => updateAndroidConfig('currency', value)}
429
851
  />
430
- <Button
431
- title="No"
432
- onPress={() => setIsRecurring(false)}
433
- color={!isRecurring ? '#2563EB' : '#ccc'}
852
+ <Text style={styles.label}>Save Card</Text>
853
+ <Switch
854
+ value={androidConfig.saveCard}
855
+ onValueChange={value => updateAndroidConfig('saveCard', value)}
856
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
857
+ thumbColor={androidConfig.saveCard ? '#fff' : '#f4f3f4'}
434
858
  />
435
- </View>
436
- </View>
859
+ <Text style={styles.label}>Save Account</Text>
860
+ <Switch
861
+ value={androidConfig.saveAccount}
862
+ onValueChange={value => updateAndroidConfig('saveAccount', value)}
863
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
864
+ thumbColor={androidConfig.saveAccount ? '#fff' : '#f4f3f4'}
865
+ />
866
+ <Text style={styles.label}>Show Receipt</Text>
867
+ <Switch
868
+ value={androidConfig.showReceipt}
869
+ onValueChange={value => updateAndroidConfig('showReceipt', value)}
870
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
871
+ thumbColor={androidConfig.showReceipt ? '#fff' : '#f4f3f4'}
872
+ />
873
+ <Text style={styles.label}>Show Donate</Text>
874
+ <Switch
875
+ value={androidConfig.showDonate}
876
+ onValueChange={value => updateAndroidConfig('showDonate', value)}
877
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
878
+ thumbColor={androidConfig.showDonate ? '#fff' : '#f4f3f4'}
879
+ />
880
+ <Text style={styles.label}>Show Total</Text>
881
+ <Switch
882
+ value={androidConfig.showTotal}
883
+ onValueChange={value => updateAndroidConfig('showTotal', value)}
884
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
885
+ thumbColor={androidConfig.showTotal ? '#fff' : '#f4f3f4'}
886
+ />
887
+ <Text style={styles.label}>Show Submit Button</Text>
888
+ <Switch
889
+ value={androidConfig.showSubmitButton}
890
+ onValueChange={value => updateAndroidConfig('showSubmitButton', value)}
891
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
892
+ thumbColor={androidConfig.showSubmitButton ? '#fff' : '#f4f3f4'}
893
+ />
894
+ <Text style={styles.label}>Name</Text>
895
+ <TextInput
896
+ style={styles.input}
897
+ value={androidConfig.name}
898
+ onChangeText={value => updateAndroidConfig('name', value)}
899
+ />
900
+ <Text style={styles.sectionTitle}>Android Fields</Text>
901
+ {androidConfig.fields.billing.map((field, index) => (
902
+ <View key={`billing-${index}`}>
903
+ <Text style={styles.label}>{`Billing ${field.name}`}</Text>
904
+ <TextInput
905
+ style={styles.input}
906
+ value={field.value}
907
+ onChangeText={value => updateAndroidConfigFields('billing', index, 'value', value)}
908
+ />
909
+ <Text style={styles.label}>{`Billing ${field.name} Required`}</Text>
910
+ <Switch
911
+ value={field.required}
912
+ onValueChange={value => updateAndroidConfigFields('billing', index, 'required', value)}
913
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
914
+ thumbColor={field.required ? '#fff' : '#f4f3f4'}
915
+ />
916
+ </View>
917
+ ))}
918
+ {androidConfig.fields.additional.map((field, index) => (
919
+ <View key={`additional-${index}`}>
920
+ <Text style={styles.label}>{`Additional ${field.name}`}</Text>
921
+ <TextInput
922
+ style={styles.input}
923
+ value={field.value}
924
+ onChangeText={value => updateAndroidConfigFields('additional', index, 'value', value)}
925
+ />
926
+ <Text style={styles.label}>{`Additional ${field.name} Required`}</Text>
927
+ <Switch
928
+ value={field.required}
929
+ onValueChange={value => updateAndroidConfigFields('additional', index, 'required', value)}
930
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
931
+ thumbColor={field.required ? '#fff' : '#f4f3f4'}
932
+ />
933
+ </View>
934
+ ))}
935
+ <Text style={styles.sectionTitle}>Android Appearance Settings</Text>
936
+ <Text style={styles.label}>Theme</Text>
937
+ <TextInput
938
+ style={styles.input}
939
+ value={androidConfig.appearanceSettings.theme}
940
+ onChangeText={value => updateAndroidConfigAppearanceSettings('theme', value)}
941
+ />
942
+ <Text style={styles.label}>Body Background Color</Text>
943
+ <TextInput
944
+ style={styles.input}
945
+ value={androidConfig.appearanceSettings.bodyBackgroundColor}
946
+ onChangeText={value => updateAndroidConfigAppearanceSettings('bodyBackgroundColor', value)}
947
+ />
948
+ <Text style={styles.label}>Container Background Color</Text>
949
+ <TextInput
950
+ style={styles.input}
951
+ value={androidConfig.appearanceSettings.containerBackgroundColor}
952
+ onChangeText={value => updateAndroidConfigAppearanceSettings('containerBackgroundColor', value)}
953
+ />
954
+ <Text style={styles.label}>Primary Font Color</Text>
955
+ <TextInput
956
+ style={styles.input}
957
+ value={androidConfig.appearanceSettings.primaryFontColor}
958
+ onChangeText={value => updateAndroidConfigAppearanceSettings('primaryFontColor', value)}
959
+ />
960
+ <Text style={styles.label}>Secondary Font Color</Text>
961
+ <TextInput
962
+ style={styles.input}
963
+ value={androidConfig.appearanceSettings.secondaryFontColor}
964
+ onChangeText={value => updateAndroidConfigAppearanceSettings('secondaryFontColor', value)}
965
+ />
966
+ <Text style={styles.label}>Primary Button Background Color</Text>
967
+ <TextInput
968
+ style={styles.input}
969
+ value={androidConfig.appearanceSettings.primaryButtonBackgroundColor}
970
+ onChangeText={value => updateAndroidConfigAppearanceSettings('primaryButtonBackgroundColor', value)}
971
+ />
972
+ <Text style={styles.label}>Primary Button Hover Color</Text>
973
+ <TextInput
974
+ style={styles.input}
975
+ value={androidConfig.appearanceSettings.primaryButtonHoverColor}
976
+ onChangeText={value => updateAndroidConfigAppearanceSettings('primaryButtonHoverColor', value)}
977
+ />
978
+ <Text style={styles.label}>Primary Button Font Color</Text>
979
+ <TextInput
980
+ style={styles.input}
981
+ value={androidConfig.appearanceSettings.primaryButtonFontColor}
982
+ onChangeText={value => updateAndroidConfigAppearanceSettings('primaryButtonFontColor', value)}
983
+ />
984
+ <Text style={styles.label}>Secondary Button Background Color</Text>
985
+ <TextInput
986
+ style={styles.input}
987
+ value={androidConfig.appearanceSettings.secondaryButtonBackgroundColor}
988
+ onChangeText={value => updateAndroidConfigAppearanceSettings('secondaryButtonBackgroundColor', value)}
989
+ />
990
+ <Text style={styles.label}>Secondary Button Hover Color</Text>
991
+ <TextInput
992
+ style={styles.input}
993
+ value={androidConfig.appearanceSettings.secondaryButtonHoverColor}
994
+ onChangeText={value => updateAndroidConfigAppearanceSettings('secondaryButtonHoverColor', value)}
995
+ />
996
+ <Text style={styles.label}>Secondary Button Font Color</Text>
997
+ <TextInput
998
+ style={styles.input}
999
+ value={androidConfig.appearanceSettings.secondaryButtonFontColor}
1000
+ onChangeText={value => updateAndroidConfigAppearanceSettings('secondaryButtonFontColor', value)}
1001
+ />
1002
+ <Text style={styles.label}>Border Radius</Text>
1003
+ <TextInput
1004
+ style={styles.input}
1005
+ value={androidConfig.appearanceSettings.borderRadius}
1006
+ onChangeText={value => updateAndroidConfigAppearanceSettings('borderRadius', value)}
1007
+ />
1008
+ <Text style={styles.label}>Font Size</Text>
1009
+ <TextInput
1010
+ style={styles.input}
1011
+ value={androidConfig.appearanceSettings.fontSize}
1012
+ onChangeText={value => updateAndroidConfigAppearanceSettings('fontSize', value)}
1013
+ />
1014
+ <Text style={styles.label}>Font Weight</Text>
1015
+ <TextInput
1016
+ style={styles.input}
1017
+ value={String(androidConfig.appearanceSettings.fontWeight)}
1018
+ onChangeText={value => updateAndroidConfigAppearanceSettings('fontWeight', parseInt(value) || '500')}
1019
+ />
1020
+ <Text style={styles.label}>Font Family</Text>
1021
+ <TextInput
1022
+ style={styles.input}
1023
+ value={androidConfig.appearanceSettings.fontFamily}
1024
+ onChangeText={value => updateAndroidConfigAppearanceSettings('fontFamily', value)}
1025
+ />
1026
+ </>
1027
+ )}
437
1028
 
438
- {Platform.OS === 'android' ? (
439
- <View style={styles.pickerContainer}>
440
- <Text style={styles.label}>Email Editable (Android):</Text>
441
- <View style={styles.buttonGroup}>
442
- <Button
443
- title="True"
444
- onPress={() => setEmailEditable(true)}
445
- color={emailEditable ? '#2563EB' : '#ccc'}
446
- />
447
- <Button
448
- title="False"
449
- onPress={() => setEmailEditable(false)}
450
- color={!emailEditable ? '#2563EB' : '#ccc'}
451
- />
452
- </View>
453
- </View>
454
- ) : (
455
- <View style={styles.pickerContainer}>
456
- <Text style={styles.label}>Allow Email (iOS):</Text>
457
- <View style={styles.buttonGroup}>
458
- <Button
459
- title="Yes"
460
- onPress={() => setIsEmail(true)}
461
- color={isEmail ? '#2563EB' : '#ccc'}
462
- />
463
- <Button
464
- title="No"
465
- onPress={() => setIsEmail(false)}
466
- color={!isEmail ? '#2563EB' : '#ccc'}
467
- />
468
- </View>
469
- </View>
1029
+ {Platform.OS === 'ios' && (
1030
+ <>
1031
+ <Text style={styles.sectionTitle}>Theme Configuration (iOS)</Text>
1032
+ <Text style={styles.label}>Body Background Color</Text>
1033
+ <TextInput
1034
+ style={styles.input}
1035
+ value={themeConfiguration.bodyBackgroundColor}
1036
+ onChangeText={value => updateThemeConfiguration('bodyBackgroundColor', value)}
1037
+ />
1038
+ <Text style={styles.label}>Container Background Color</Text>
1039
+ <TextInput
1040
+ style={styles.input}
1041
+ value={themeConfiguration.containerBackgroundColor}
1042
+ onChangeText={value => updateThemeConfiguration('containerBackgroundColor', value)}
1043
+ />
1044
+ <Text style={styles.label}>Primary Font Color</Text>
1045
+ <TextInput
1046
+ style={styles.input}
1047
+ value={themeConfiguration.primaryFontColor}
1048
+ onChangeText={value => updateThemeConfiguration('primaryFontColor', value)}
1049
+ />
1050
+ <Text style={styles.label}>Secondary Font Color</Text>
1051
+ <TextInput
1052
+ style={styles.input}
1053
+ value={themeConfiguration.secondaryFontColor}
1054
+ onChangeText={value => updateThemeConfiguration('secondaryFontColor', value)}
1055
+ />
1056
+ <Text style={styles.label}>Primary Button Background Color</Text>
1057
+ <TextInput
1058
+ style={styles.input}
1059
+ value={themeConfiguration.primaryButtonBackgroundColor}
1060
+ onChangeText={value => updateThemeConfiguration('primaryButtonBackgroundColor', value)}
1061
+ />
1062
+ <Text style={styles.label}>Primary Button Hover Color</Text>
1063
+ <TextInput
1064
+ style={styles.input}
1065
+ value={themeConfiguration.primaryButtonHoverColor}
1066
+ onChangeText={value => updateThemeConfiguration('primaryButtonHoverColor', value)}
1067
+ />
1068
+ <Text style={styles.label}>Primary Button Font Color</Text>
1069
+ <TextInput
1070
+ style={styles.input}
1071
+ value={themeConfiguration.primaryButtonFontColor}
1072
+ onChangeText={value => updateThemeConfiguration('primaryButtonFontColor', value)}
1073
+ />
1074
+ <Text style={styles.label}>Secondary Button Background Color</Text>
1075
+ <TextInput
1076
+ style={styles.input}
1077
+ value={themeConfiguration.secondaryButtonBackgroundColor}
1078
+ onChangeText={value => updateThemeConfiguration('secondaryButtonBackgroundColor', value)}
1079
+ />
1080
+ <Text style={styles.label}>Secondary Button Hover Color</Text>
1081
+ <TextInput
1082
+ style={styles.input}
1083
+ value={themeConfiguration.secondaryButtonHoverColor}
1084
+ onChangeText={value => updateThemeConfiguration('secondaryButtonHoverColor', value)}
1085
+ />
1086
+ <Text style={styles.label}>Secondary Button Font Color</Text>
1087
+ <TextInput
1088
+ style={styles.input}
1089
+ value={themeConfiguration.secondaryButtonFontColor}
1090
+ onChangeText={value => updateThemeConfiguration('secondaryButtonFontColor', value)}
1091
+ />
1092
+ <Text style={styles.label}>Border Radius</Text>
1093
+ <TextInput
1094
+ style={styles.input}
1095
+ value={themeConfiguration.borderRadius}
1096
+ onChangeText={value => updateThemeConfiguration('borderRadius', value)}
1097
+ />
1098
+ <Text style={styles.label}>Font Size</Text>
1099
+ <TextInput
1100
+ style={styles.input}
1101
+ value={themeConfiguration.fontSize}
1102
+ onChangeText={value => updateThemeConfiguration('fontSize', value)}
1103
+ />
1104
+ <Text style={styles.label}>Font Weight</Text>
1105
+ <TextInput
1106
+ style={styles.input}
1107
+ value={String(themeConfiguration.fontWeight)}
1108
+ onChangeText={value => updateThemeConfiguration('fontWeight', parseInt(value) || 500)}
1109
+ />
1110
+ <Text style={styles.label}>Font Family</Text>
1111
+ <TextInput
1112
+ style={styles.input}
1113
+ value={themeConfiguration.fontFamily}
1114
+ onChangeText={value => updateThemeConfiguration('fontFamily', value)}
1115
+ />
1116
+ </>
470
1117
  )}
471
1118
 
1119
+ <Text style={styles.sectionTitle}>GrailPay Parameters</Text>
1120
+ <Text style={styles.label}>Role</Text>
1121
+ <TextInput
1122
+ style={styles.input}
1123
+ value={grailPayParams.role}
1124
+ onChangeText={value => updateGrailPayParams('role', value)}
1125
+ />
1126
+ <Text style={styles.label}>Timeout</Text>
1127
+ <TextInput
1128
+ style={styles.input}
1129
+ value={String(grailPayParams.timeout)}
1130
+ onChangeText={value => updateGrailPayParams('timeout', parseInt(value) || 10)}
1131
+ />
1132
+ <Text style={styles.label}>Is Sandbox</Text>
1133
+ <Switch
1134
+ value={grailPayParams.isSandbox}
1135
+ onValueChange={value => updateGrailPayParams('isSandbox', value)}
1136
+ trackColor={{ false: '#ccc', true: '#2563EB' }}
1137
+ thumbColor={grailPayParams.isSandbox ? '#fff' : '#f4f3f4'}
1138
+ />
1139
+ <Text style={styles.label}>Branding Name</Text>
1140
+ <TextInput
1141
+ style={styles.input}
1142
+ value={grailPayParams.brandingName}
1143
+ onChangeText={value => updateGrailPayParams('brandingName', value)}
1144
+ />
1145
+ <Text style={styles.label}>Finder Subtitle</Text>
1146
+ <TextInput
1147
+ style={styles.input}
1148
+ value={grailPayParams.finderSubtitle}
1149
+ onChangeText={value => updateGrailPayParams('finderSubtitle', value)}
1150
+ />
1151
+ <Text style={styles.label}>Search Placeholder</Text>
1152
+ <TextInput
1153
+ style={styles.input}
1154
+ value={grailPayParams.searchPlaceholder}
1155
+ onChangeText={value => updateGrailPayParams('searchPlaceholder', value)}
1156
+ />
1157
+
1158
+ <Text style={styles.sectionTitle}>Recurring Data</Text>
1159
+ <Text style={styles.label}>Allow Cycles</Text>
1160
+ <TextInput
1161
+ style={styles.input}
1162
+ value={String(recurringData.allowCycles)}
1163
+ onChangeText={value => updateRecurringData('allowCycles', parseInt(value) || 2)}
1164
+ />
1165
+ <Text style={styles.label}>Intervals</Text>
472
1166
  <View style={styles.buttonGroup}>
473
- <Button title="Pay" onPress={handlePayment} />
474
- <Button title="Payment Ref" onPress={handlePaymentReference} />
1167
+ <Button
1168
+ title="Weekly"
1169
+ onPress={() => toggleInterval('weekly')}
1170
+ color={recurringData.intervals.includes('weekly') ? '#2563EB' : '#ccc'}
1171
+ />
1172
+ <Button
1173
+ title="Monthly"
1174
+ onPress={() => toggleInterval('monthly')}
1175
+ color={recurringData.intervals.includes('monthly') ? '#2563EB' : '#ccc'}
1176
+ />
1177
+ </View>
1178
+ <Text style={styles.label}>Recurring Start Type</Text>
1179
+ <TextInput
1180
+ style={styles.input}
1181
+ value={recurringData.recurringStartType}
1182
+ onChangeText={value => updateRecurringData('recurringStartType', value)}
1183
+ />
1184
+ <Text style={styles.label}>Recurring Start Date</Text>
1185
+ <TextInput
1186
+ style={styles.input}
1187
+ value={recurringData.recurringStartDate}
1188
+ onChangeText={value => updateRecurringData('recurringStartDate', value)}
1189
+ />
1190
+
1191
+ <View style={styles.buttonGroup}>
1192
+ <Button title="Pay" onPress={handlePayment} />
1193
+ {Platform.OS === 'ios' ? (
1194
+ <Button title="Payment Ref" onPress={handlePaymentReference} disabled={loading} />
1195
+ ) : (
1196
+ <></>
1197
+ )
1198
+ }
475
1199
  </View>
476
1200
 
477
1201
  <Text selectable style={styles.result}>{result}</Text>
@@ -492,29 +1216,62 @@ const styles = StyleSheet.create({
492
1216
  marginTop: 50,
493
1217
  textAlign: 'center',
494
1218
  },
1219
+ sectionTitle: {
1220
+ fontSize: 20,
1221
+ fontWeight: 'bold',
1222
+ marginTop: 20,
1223
+ marginBottom: 10,
1224
+ },
495
1225
  input: {
496
1226
  height: 40,
497
1227
  borderColor: '#ccc',
498
1228
  borderWidth: 1,
499
1229
  borderRadius: 5,
500
1230
  paddingHorizontal: 10,
501
- marginBottom: 20,
1231
+ marginBottom: 10,
502
1232
  },
503
1233
  pickerContainer: {
504
1234
  marginBottom: 20,
505
1235
  },
1236
+ toggleContainer: {
1237
+ flexDirection: 'row',
1238
+ justifyContent: 'space-between',
1239
+ alignItems: 'center',
1240
+ marginBottom: 10,
1241
+ },
506
1242
  label: {
507
1243
  fontSize: 16,
508
- marginBottom: 8,
509
1244
  fontWeight: '500',
1245
+ marginBottom: 5,
510
1246
  },
511
1247
  buttonGroup: {
512
1248
  flexDirection: 'row',
513
1249
  justifyContent: 'space-between',
514
1250
  marginBottom: 20,
1251
+ marginTop: 20,
515
1252
  gap: 10,
1253
+
1254
+ },
1255
+ result: {
1256
+ fontSize: 14,
1257
+ fontFamily: 'monospace',
1258
+ color: '#333',
1259
+ marginTop: 20,
1260
+ },
1261
+ environmentButton: {
1262
+ flex: 1,
1263
+ paddingVertical: 10,
1264
+ paddingHorizontal: 20,
1265
+ borderRadius: 5,
1266
+ marginHorizontal: 5,
1267
+ alignItems: 'center',
1268
+ justifyContent: 'center',
1269
+ },
1270
+ buttonText: {
1271
+ color: '#fff',
1272
+ fontSize: 16,
1273
+ fontWeight: '500',
516
1274
  },
517
- result: { fontSize: 14, fontFamily: 'monospace', color: '#333' },
518
1275
  });
519
1276
 
520
1277
  ```