floating-games-sdk 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.
Files changed (77) hide show
  1. package/package.json +44 -0
  2. package/src/FloatingGames.tsx +25 -0
  3. package/src/assets/fonts/Creepster-Regular.ttf +0 -0
  4. package/src/assets/images/android-icon-background.png +0 -0
  5. package/src/assets/images/android-icon-foreground.png +0 -0
  6. package/src/assets/images/android-icon-monochrome.png +0 -0
  7. package/src/assets/images/blocks-icon.png +0 -0
  8. package/src/assets/images/bright-rubber-puzzles-blue.png +0 -0
  9. package/src/assets/images/close.png +0 -0
  10. package/src/assets/images/eriri.png +0 -0
  11. package/src/assets/images/favicon.png +0 -0
  12. package/src/assets/images/first-play.png +0 -0
  13. package/src/assets/images/game-over.gif +0 -0
  14. package/src/assets/images/game-pad.png +0 -0
  15. package/src/assets/images/game-pad2.png +0 -0
  16. package/src/assets/images/game-page-bg1.png +0 -0
  17. package/src/assets/images/hands-down-bg.png +0 -0
  18. package/src/assets/images/icon.png +0 -0
  19. package/src/assets/images/lets-play.gif +0 -0
  20. package/src/assets/images/lucky-day.gif +0 -0
  21. package/src/assets/images/maths.png +0 -0
  22. package/src/assets/images/not-playing.png +0 -0
  23. package/src/assets/images/number-puzzle-select.png +0 -0
  24. package/src/assets/images/number-puzzle-selector.png +0 -0
  25. package/src/assets/images/pause-clock.png +0 -0
  26. package/src/assets/images/pause-icon.png +0 -0
  27. package/src/assets/images/play-icon.png +0 -0
  28. package/src/assets/images/play-now.gif +0 -0
  29. package/src/assets/images/play-play.png +0 -0
  30. package/src/assets/images/play.png +0 -0
  31. package/src/assets/images/quit-game.png +0 -0
  32. package/src/assets/images/quit-icon.png +0 -0
  33. package/src/assets/images/quit.png +0 -0
  34. package/src/assets/images/review-win-selector.png +0 -0
  35. package/src/assets/images/select-bg.png +0 -0
  36. package/src/assets/images/select-logo.png +0 -0
  37. package/src/assets/images/spin-wheel-select.png +0 -0
  38. package/src/assets/images/spin-wheel-selector.png +0 -0
  39. package/src/assets/images/splash-icon.png +0 -0
  40. package/src/assets/images/start-button.png +0 -0
  41. package/src/assets/images/start-game.png +0 -0
  42. package/src/assets/images/stop-quit.png +0 -0
  43. package/src/assets/images/waiting-for-you.gif +0 -0
  44. package/src/assets/sounds/selector-music.mp3 +0 -0
  45. package/src/assets/sounds/timeup-sound.wav +0 -0
  46. package/src/components/atoms/Amount.tsx +48 -0
  47. package/src/components/atoms/FloatingMenu.tsx +119 -0
  48. package/src/components/atoms/ShimmerHR.tsx +64 -0
  49. package/src/components/atoms/UseAnimatedCounter.tsx +31 -0
  50. package/src/components/games/Chain.tsx +26 -0
  51. package/src/components/games/GameItem.tsx +38 -0
  52. package/src/components/games/GameSelectorScreen.tsx +221 -0
  53. package/src/components/games/GameSplash.tsx +44 -0
  54. package/src/components/games/HangingSign.tsx +75 -0
  55. package/src/components/games/SplashScreen.tsx +69 -0
  56. package/src/components/games/number-puzzle/DragTile.tsx +65 -0
  57. package/src/components/games/number-puzzle/GameScreen.tsx +597 -0
  58. package/src/components/games/number-puzzle/PuzzleSplash.tsx +50 -0
  59. package/src/components/games/number-puzzle/TileComponent.tsx +47 -0
  60. package/src/components/games/review-and-win/EmojiTracker.tsx +96 -0
  61. package/src/components/games/review-and-win/GameScreen.tsx +135 -0
  62. package/src/components/games/review-and-win/Tile.tsx +60 -0
  63. package/src/components/games/spin-wheel/SpinAndWin.tsx +507 -0
  64. package/src/components/payment/CheckoutScreen.tsx +50 -0
  65. package/src/components/payment/FundAccount.tsx +281 -0
  66. package/src/components/payment/Payment.tsx +45 -0
  67. package/src/components/reusables/AppSelect.tsx +70 -0
  68. package/src/components/reusables/CountdownTimer.tsx +116 -0
  69. package/src/components/reusables/FloatingButton.tsx +71 -0
  70. package/src/components/reusables/SoundPlayer.ts +28 -0
  71. package/src/components/utils/shuffle.ts +48 -0
  72. package/src/context/GameContext.tsx +15 -0
  73. package/src/index.tsx +5 -0
  74. package/src/modals/BottomSheetModal.tsx +38 -0
  75. package/src/modals/GameOverModal.tsx +76 -0
  76. package/src/modals/PauseModal.tsx +95 -0
  77. package/src/navigation/GameNavigator.tsx +48 -0
@@ -0,0 +1,507 @@
1
+ import React, { useState, useRef, useEffect } from "react";
2
+ import {
3
+ View,
4
+ Text,
5
+ TouchableOpacity,
6
+ StyleSheet,
7
+ Animated,
8
+ Easing,
9
+ ScrollView,
10
+ Dimensions,
11
+ } from "react-native";
12
+ import Svg, { G, Path, Text as SvgText, Circle } from "react-native-svg";
13
+
14
+ const { width: SCREEN_WIDTH } = Dimensions.get("window");
15
+ const WHEEL_SIZE = Math.min(SCREEN_WIDTH - 48, 320);
16
+ const RADIUS = WHEEL_SIZE / 2 - 4;
17
+ const CX = WHEEL_SIZE / 2;
18
+ const CY = WHEEL_SIZE / 2;
19
+
20
+ interface Segment {
21
+ label: string;
22
+ color: string;
23
+ textColor: string;
24
+ }
25
+
26
+ interface HistoryItem {
27
+ label: string;
28
+ color: string;
29
+ pts: number;
30
+ }
31
+
32
+ const SEGMENTS: Segment[] = [
33
+ { label: "🎁 50 pts", color: "#FF6B6B", textColor: "#fff" },
34
+ { label: "💀 Lose", color: "#2C2C3E", textColor: "#aaa" },
35
+ { label: "⭐ 200 pts", color: "#FFD93D", textColor: "#1a1a2e" },
36
+ { label: "🔄 Retry", color: "#6BCB77", textColor: "#fff" },
37
+ { label: "💎 500 pts", color: "#4D96FF", textColor: "#fff" },
38
+ { label: "💀 Lose", color: "#2C2C3E", textColor: "#aaa" },
39
+ { label: "🎯 100 pts", color: "#C77DFF", textColor: "#fff" },
40
+ { label: "🍀 Jackpot", color: "#FF9F1C", textColor: "#fff" },
41
+ ];
42
+
43
+ const NUM_SEGMENTS = SEGMENTS.length;
44
+ const ANGLE_PER_SEGMENT = 360 / NUM_SEGMENTS;
45
+
46
+ function getPointValue(label: string): number {
47
+ if (label.includes("500")) return 500;
48
+ if (label.includes("200")) return 200;
49
+ if (label.includes("100")) return 100;
50
+ if (label.includes("50")) return 50;
51
+ if (label.includes("Jackpot")) return 1000;
52
+ if (label.includes("Lose")) return -999;
53
+ if (label.includes("Retry")) return -998;
54
+ return 0;
55
+ }
56
+
57
+ function polarToCartesian(
58
+ cx: number,
59
+ cy: number,
60
+ r: number,
61
+ angleDeg: number
62
+ ): { x: number; y: number } {
63
+ const angleRad = (angleDeg * Math.PI) / 180;
64
+ return {
65
+ x: cx + r * Math.cos(angleRad),
66
+ y: cy + r * Math.sin(angleRad),
67
+ };
68
+ }
69
+
70
+ function buildSegmentPath(
71
+ index: number,
72
+ cx: number,
73
+ cy: number,
74
+ radius: number
75
+ ): string {
76
+ const startAngle = index * ANGLE_PER_SEGMENT;
77
+ const endAngle = (index + 1) * ANGLE_PER_SEGMENT;
78
+ const start = polarToCartesian(cx, cy, radius, startAngle);
79
+ const end = polarToCartesian(cx, cy, radius, endAngle);
80
+ const largeArc = ANGLE_PER_SEGMENT > 180 ? 1 : 0;
81
+ return `M ${cx} ${cy} L ${start.x} ${start.y} A ${radius} ${radius} 0 ${largeArc} 1 ${end.x} ${end.y} Z`;
82
+ }
83
+
84
+ function getLabelPosition(
85
+ index: number,
86
+ cx: number,
87
+ cy: number,
88
+ radius: number
89
+ ): { x: number; y: number; rotation: number } {
90
+ const midAngle = index * ANGLE_PER_SEGMENT + ANGLE_PER_SEGMENT / 2;
91
+ const labelRadius = radius * 0.65;
92
+ const pos = polarToCartesian(cx, cy, labelRadius, midAngle);
93
+ return { x: pos.x, y: pos.y, rotation: midAngle };
94
+ }
95
+
96
+ const WheelSvg: React.FC = () => (
97
+ <Svg width={WHEEL_SIZE} height={WHEEL_SIZE}>
98
+ {SEGMENTS.map((seg, i) => {
99
+ const path = buildSegmentPath(i, CX, CY, RADIUS);
100
+ const { x, y, rotation } = getLabelPosition(i, CX, CY, RADIUS);
101
+ return (
102
+ <G key={i}>
103
+ <Path
104
+ d={path}
105
+ fill={seg.color}
106
+ stroke="#1a1a2e"
107
+ strokeWidth={2}
108
+ />
109
+ <SvgText
110
+ x={x}
111
+ y={y}
112
+ fill={seg.textColor}
113
+ fontSize={11}
114
+ fontWeight="bold"
115
+ textAnchor="middle"
116
+ alignmentBaseline="middle"
117
+ rotation={rotation}
118
+ origin={`${x}, ${y}`}
119
+ >
120
+ {seg.label}
121
+ </SvgText>
122
+ </G>
123
+ );
124
+ })}
125
+ {/* Center circle */}
126
+ <Circle cx={CX} cy={CY} r={22} fill="#1a1a2e" stroke="#FFD93D" strokeWidth={3} />
127
+ <Circle cx={CX} cy={CY} r={8} fill="#FFD93D" />
128
+ </Svg>
129
+ );
130
+
131
+ export default function SpinAndWin(): React.JSX.Element {
132
+ const [spinning, setSpinning] = useState<boolean>(false);
133
+ const [result, setResult] = useState<Segment | null>(null);
134
+ const [score, setScore] = useState<number>(0);
135
+ const [spins, setSpins] = useState<number>(0);
136
+ const [showResult, setShowResult] = useState<boolean>(false);
137
+ const [history, setHistory] = useState<HistoryItem[]>([]);
138
+
139
+ const spinAnim = useRef(new Animated.Value(0)).current;
140
+ const currentRotation = useRef<number>(0);
141
+ const resultAnim = useRef(new Animated.Value(0)).current;
142
+
143
+ const spin = (): void => {
144
+ if (spinning) return;
145
+ setSpinning(true);
146
+ setShowResult(false);
147
+ setResult(null);
148
+
149
+ const extraSpins = 5 + Math.floor(Math.random() * 5);
150
+ const randomAngle = Math.floor(Math.random() * 360);
151
+ const totalRotation = extraSpins * 360 + randomAngle;
152
+ const newRotation = currentRotation.current + totalRotation;
153
+
154
+ spinAnim.setValue(currentRotation.current);
155
+ currentRotation.current = newRotation;
156
+
157
+ Animated.timing(spinAnim, {
158
+ toValue: newRotation,
159
+ duration: 4000,
160
+ easing: Easing.out(Easing.cubic),
161
+ useNativeDriver: true,
162
+ }).start(() => {
163
+ const normalized = newRotation % 360;
164
+ const pointerAngle = (360 - normalized + 270) % 360;
165
+ const segmentIndex =
166
+ Math.floor(pointerAngle / ANGLE_PER_SEGMENT) % NUM_SEGMENTS;
167
+ const segment = SEGMENTS[segmentIndex];
168
+ const pts = getPointValue(segment.label);
169
+
170
+ setResult(segment);
171
+ setSpinning(false);
172
+ setSpins((s) => s + 1);
173
+ setShowResult(true);
174
+
175
+ resultAnim.setValue(0);
176
+ Animated.spring(resultAnim, {
177
+ toValue: 1,
178
+ friction: 5,
179
+ tension: 200,
180
+ useNativeDriver: true,
181
+ }).start();
182
+
183
+ if (pts >= 0) {
184
+ setScore((prev) => prev + pts);
185
+ }
186
+
187
+ setHistory((prev) => [
188
+ { label: segment.label, color: segment.color, pts },
189
+ ...prev.slice(0, 4),
190
+ ]);
191
+ });
192
+ };
193
+
194
+ const reset = (): void => {
195
+ setScore(0);
196
+ setSpins(0);
197
+ setHistory([]);
198
+ setResult(null);
199
+ setShowResult(false);
200
+ spinAnim.setValue(0);
201
+ currentRotation.current = 0;
202
+ };
203
+
204
+ const rotate = spinAnim.interpolate({
205
+ inputRange: [0, 360],
206
+ outputRange: ["0deg", "360deg"],
207
+ });
208
+
209
+ const resultScale = resultAnim.interpolate({
210
+ inputRange: [0, 1],
211
+ outputRange: [0.6, 1],
212
+ });
213
+
214
+ const bestScore =
215
+ history.length > 0
216
+ ? Math.max(...history.filter((h) => h.pts >= 0).map((h) => h.pts), 0)
217
+ : 0;
218
+
219
+ return (
220
+ <ScrollView
221
+ style={styles.root}
222
+ contentContainerStyle={styles.scrollContent}
223
+ showsVerticalScrollIndicator={false}
224
+ >
225
+ {/* Header */}
226
+ <View style={styles.header}>
227
+ <View style={styles.titleRow}>
228
+ {/*<Text style={styles.titleIcon}>🎰</Text>*/}
229
+ <Text style={styles.title}>SPIN & WIN</Text>
230
+ {/*<Text style={styles.titleIcon}>🎰</Text>*/}
231
+ </View>
232
+ <Text style={styles.subtitle}>Your luck is just one spin away</Text>
233
+ </View>
234
+
235
+ {/* Score Bar */}
236
+ <View style={styles.scoreBar}>
237
+ <View style={styles.scoreItem}>
238
+ <Text style={styles.scoreLabel}>SCORE</Text>
239
+ <Text style={styles.scoreValue}>{score.toLocaleString()}</Text>
240
+ </View>
241
+ <View style={styles.scoreDivider} />
242
+ <View style={styles.scoreItem}>
243
+ <Text style={styles.scoreLabel}>SPINS</Text>
244
+ <Text style={styles.scoreValue}>{spins}</Text>
245
+ </View>
246
+ <View style={styles.scoreDivider} />
247
+ <View style={styles.scoreItem}>
248
+ <Text style={styles.scoreLabel}>BEST</Text>
249
+ <Text style={styles.scoreValue}>{bestScore}</Text>
250
+ </View>
251
+ </View>
252
+
253
+ {/* Wheel Area */}
254
+ <View style={styles.wheelArea}>
255
+ <Text style={styles.pointer}>▼</Text>
256
+ <View style={styles.wheelGlow}>
257
+ <Animated.View style={{ transform: [{ rotate }] }}>
258
+ <WheelSvg />
259
+ </Animated.View>
260
+ </View>
261
+ </View>
262
+
263
+ {/* Result Banner */}
264
+ {showResult && result && (
265
+ <Animated.View
266
+ style={[
267
+ styles.resultBanner,
268
+ { backgroundColor: result.color },
269
+ { transform: [{ scale: resultScale }] },
270
+ ]}
271
+ >
272
+ <Text style={[styles.resultText, { color: result.textColor }]}>
273
+ {result.label}
274
+ </Text>
275
+ {getPointValue(result.label) >= 0 && (
276
+ <Text style={[styles.resultSub, { color: result.textColor }]}>
277
+ {getPointValue(result.label) === 1000
278
+ ? "🎉 JACKPOT!"
279
+ : `+${getPointValue(result.label)} points`}
280
+ </Text>
281
+ )}
282
+ {getPointValue(result.label) === -999 && (
283
+ <Text style={[styles.resultSub, { color: result.textColor }]}>
284
+ Better luck next time!
285
+ </Text>
286
+ )}
287
+ {getPointValue(result.label) === -998 && (
288
+ <Text style={[styles.resultSub, { color: result.textColor }]}>
289
+ Spin again for free!
290
+ </Text>
291
+ )}
292
+ </Animated.View>
293
+ )}
294
+
295
+ {/* Spin Button */}
296
+ <TouchableOpacity
297
+ onPress={spin}
298
+ disabled={spinning}
299
+ activeOpacity={0.8}
300
+ style={[styles.spinBtn, spinning && styles.spinBtnDisabled]}
301
+ >
302
+ <Text style={styles.spinBtnText}>
303
+ {spinning ? "⏳ Spinning..." : "🎯 SPIN!"}
304
+ </Text>
305
+ </TouchableOpacity>
306
+
307
+ {/* History */}
308
+ {history.length > 0 && (
309
+ <View style={styles.historySection}>
310
+ <Text style={styles.historyTitle}>Recent Spins</Text>
311
+ <View style={styles.historyList}>
312
+ {history.map((h, i) => (
313
+ <View
314
+ key={i}
315
+ style={[
316
+ styles.historyChip,
317
+ { backgroundColor: h.color, opacity: 1 - i * 0.15 },
318
+ ]}
319
+ >
320
+ <Text style={styles.historyChipText}>{h.label}</Text>
321
+ </View>
322
+ ))}
323
+ </View>
324
+ </View>
325
+ )}
326
+
327
+ {/* Reset */}
328
+ {spins > 0 && (
329
+ <TouchableOpacity onPress={reset} style={styles.resetBtn} activeOpacity={0.7}>
330
+ <Text style={styles.resetBtnText}>↺ Reset Game</Text>
331
+ </TouchableOpacity>
332
+ )}
333
+ </ScrollView>
334
+ );
335
+ }
336
+
337
+ const styles = StyleSheet.create({
338
+ root: {
339
+ flex: 1,
340
+ // backgroundColor: "#0d0d1a",
341
+ backgroundColor: "#3b5e59",
342
+ },
343
+ scrollContent: {
344
+ alignItems: "center",
345
+ paddingVertical: 40,
346
+ paddingHorizontal: 16,
347
+ gap: 20,
348
+ },
349
+ header: {
350
+ alignItems: "center",
351
+ },
352
+ titleRow: {
353
+ flexDirection: "row",
354
+ alignItems: "center",
355
+ gap: 12,
356
+ },
357
+ titleIcon: {
358
+ fontSize: 28,
359
+ },
360
+ title: {
361
+ fontSize: 22,
362
+ fontWeight: "900",
363
+ color: "#FFD93D",
364
+ letterSpacing: 4,
365
+ },
366
+ subtitle: {
367
+ color: "#aaa",
368
+ marginTop: 4,
369
+ fontSize: 13,
370
+ letterSpacing: 1,
371
+ },
372
+ scoreBar: {
373
+ backgroundColor: "#1d4540",
374
+ borderWidth: 1,
375
+ borderColor: "#2a2a45",
376
+ borderRadius: 16,
377
+ flexDirection: "row",
378
+ alignItems: "center",
379
+ paddingVertical: 12,
380
+ paddingHorizontal: 28,
381
+ gap: 24,
382
+ width: "100%",
383
+ },
384
+ scoreItem: {
385
+ flex: 1,
386
+ alignItems: "center",
387
+ },
388
+ scoreLabel: {
389
+ fontSize: 10,
390
+ color: "#aaa",
391
+ letterSpacing: 2,
392
+ fontWeight: "700",
393
+ },
394
+ scoreValue: {
395
+ fontSize: 22,
396
+ fontWeight: "800",
397
+ color: "#FFD93D",
398
+ marginTop: 2,
399
+ },
400
+ scoreDivider: {
401
+ width: 1,
402
+ height: 36,
403
+ backgroundColor: "#2a2a45",
404
+ },
405
+ wheelArea: {
406
+ alignItems: "center",
407
+ justifyContent: "center",
408
+ marginTop: 8,
409
+ },
410
+ pointer: {
411
+ fontSize: 28,
412
+ color: "#FFD93D",
413
+ marginBottom: -4,
414
+ zIndex: 10,
415
+ textShadowColor: "#FFD93D88",
416
+ textShadowOffset: { width: 0, height: 2 },
417
+ textShadowRadius: 8,
418
+ },
419
+ wheelGlow: {
420
+ borderRadius: WHEEL_SIZE / 2 + 6,
421
+ padding: 6,
422
+ backgroundColor: "transparent",
423
+ shadowColor: "#FFD93D",
424
+ shadowOffset: { width: 0, height: 0 },
425
+ shadowOpacity: 0.5,
426
+ shadowRadius: 20,
427
+ elevation: 10,
428
+ borderWidth: 2,
429
+ borderColor: "#FFD93D44",
430
+ },
431
+ resultBanner: {
432
+ borderRadius: 14,
433
+ paddingVertical: 14,
434
+ paddingHorizontal: 28,
435
+ alignItems: "center",
436
+ width: "100%",
437
+ },
438
+ resultText: {
439
+ fontSize: 22,
440
+ fontWeight: "800",
441
+ letterSpacing: 1,
442
+ },
443
+ resultSub: {
444
+ fontSize: 13,
445
+ marginTop: 4,
446
+ opacity: 0.85,
447
+ },
448
+ spinBtn: {
449
+ backgroundColor: "#FFD93D",
450
+ borderRadius: 50,
451
+ paddingVertical: 16,
452
+ paddingHorizontal: 60,
453
+ shadowColor: "#FFD93D",
454
+ shadowOffset: { width: 0, height: 4 },
455
+ shadowOpacity: 0.5,
456
+ shadowRadius: 12,
457
+ elevation: 8,
458
+ },
459
+ spinBtnDisabled: {
460
+ opacity: 0.6,
461
+ },
462
+ spinBtnText: {
463
+ fontSize: 15,
464
+ fontWeight: "900",
465
+ color: "#1a1a2e",
466
+ letterSpacing: 2,
467
+ },
468
+ historySection: {
469
+ width: "100%",
470
+ alignItems: "center",
471
+ },
472
+ historyTitle: {
473
+ color: "#555",
474
+ fontSize: 11,
475
+ letterSpacing: 2,
476
+ textTransform: "uppercase",
477
+ marginBottom: 8,
478
+ },
479
+ historyList: {
480
+ flexDirection: "row",
481
+ gap: 8,
482
+ justifyContent: "center",
483
+ flexWrap: "wrap",
484
+ },
485
+ historyChip: {
486
+ borderRadius: 20,
487
+ paddingVertical: 5,
488
+ paddingHorizontal: 14,
489
+ },
490
+ historyChipText: {
491
+ fontSize: 12,
492
+ fontWeight: "700",
493
+ color: "#fff",
494
+ },
495
+ resetBtn: {
496
+ backgroundColor: "transparent",
497
+ borderWidth: 1,
498
+ borderColor: "#2a2a45",
499
+ borderRadius: 8,
500
+ paddingVertical: 8,
501
+ paddingHorizontal: 20,
502
+ },
503
+ resetBtnText: {
504
+ color: "#eee",
505
+ fontSize: 13,
506
+ },
507
+ });
@@ -0,0 +1,50 @@
1
+ // import React from 'react';
2
+ // import { Button } from 'react-native';
3
+ // import { presentPayment } from '@netappsng/react-native-pay';
4
+ // import type { PaymentConfig } from '@netappsng/react-native-pay';
5
+ //
6
+ // type Props = {
7
+ // amount: number;
8
+ // };
9
+ //
10
+ // export function CheckoutScreen({ amount }: Props) {
11
+ // function handlePayment() {
12
+ // const amountNaira = amount;
13
+ // const amountKobo = Math.round(amountNaira * 100);
14
+ //
15
+ // const config: PaymentConfig = {
16
+ // publicKey: 'pk_live_880c15c51cbc19e38c44f44a54fd628d801b05b2ef8d35e4',
17
+ // amount: amountKobo,
18
+ // currency: 'NGN',
19
+ // email: 'john@example.com',
20
+ // fullName: 'John Doe',
21
+ // phoneNumber: '08106720418',
22
+ // narration: 'Dev Test Payment',
23
+ // paymentChannels: ['card', 'transfer', 'ussd', 'payattitude', 'moniflow'],
24
+ // defaultChannel: 'card',
25
+ // address1: 'Customer Address',
26
+ // metadata: { inputAmount: amountNaira, env: 'development' },
27
+ // businessName: 'Demo Store',
28
+ // showTransactionSummary: true,
29
+ // };
30
+ //
31
+ // const cleanup = presentPayment(config, {
32
+ // onSuccess: (payload) => {
33
+ // console.log('Payment successful!', payload.transactionRef);
34
+ // },
35
+ // onFailed: (payload) => {
36
+ // console.log('Payment failed:', payload.message);
37
+ // },
38
+ // onCancel: () => {
39
+ // console.log('Payment cancelled');
40
+ // },
41
+ // onReady: () => {
42
+ // console.log('Payment UI ready');
43
+ // },
44
+ // });
45
+ //
46
+ // return cleanup; // optional but good practice
47
+ // }
48
+ //
49
+ // return <Button title={`Pay ₦${amount}`} onPress={handlePayment} />;
50
+ // }