@clockpay/react-native 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 (109) hide show
  1. package/README.md +113 -0
  2. package/lib/commonjs/api/client.js +73 -0
  3. package/lib/commonjs/api/client.js.map +1 -0
  4. package/lib/commonjs/api/endpoints.js +11 -0
  5. package/lib/commonjs/api/endpoints.js.map +1 -0
  6. package/lib/commonjs/components/bottom-sheet.js +137 -0
  7. package/lib/commonjs/components/bottom-sheet.js.map +1 -0
  8. package/lib/commonjs/components/icons.js +129 -0
  9. package/lib/commonjs/components/icons.js.map +1 -0
  10. package/lib/commonjs/components/payment-button.js +106 -0
  11. package/lib/commonjs/components/payment-button.js.map +1 -0
  12. package/lib/commonjs/components/payment-sheet.js +156 -0
  13. package/lib/commonjs/components/payment-sheet.js.map +1 -0
  14. package/lib/commonjs/components/views/status-view.js +109 -0
  15. package/lib/commonjs/components/views/status-view.js.map +1 -0
  16. package/lib/commonjs/components/views/transfer-view.js +162 -0
  17. package/lib/commonjs/components/views/transfer-view.js.map +1 -0
  18. package/lib/commonjs/components/views/verify-view.js +98 -0
  19. package/lib/commonjs/components/views/verify-view.js.map +1 -0
  20. package/lib/commonjs/hooks/use-countdown.js +24 -0
  21. package/lib/commonjs/hooks/use-countdown.js.map +1 -0
  22. package/lib/commonjs/index.js +13 -0
  23. package/lib/commonjs/index.js.map +1 -0
  24. package/lib/commonjs/internal/constants.js +42 -0
  25. package/lib/commonjs/internal/constants.js.map +1 -0
  26. package/lib/commonjs/internal/format.js +29 -0
  27. package/lib/commonjs/internal/format.js.map +1 -0
  28. package/lib/commonjs/internal/theme.js +24 -0
  29. package/lib/commonjs/internal/theme.js.map +1 -0
  30. package/lib/commonjs/package.json +1 -0
  31. package/lib/commonjs/types.js +6 -0
  32. package/lib/commonjs/types.js.map +1 -0
  33. package/lib/module/api/client.js +67 -0
  34. package/lib/module/api/client.js.map +1 -0
  35. package/lib/module/api/endpoints.js +7 -0
  36. package/lib/module/api/endpoints.js.map +1 -0
  37. package/lib/module/components/bottom-sheet.js +133 -0
  38. package/lib/module/components/bottom-sheet.js.map +1 -0
  39. package/lib/module/components/icons.js +120 -0
  40. package/lib/module/components/icons.js.map +1 -0
  41. package/lib/module/components/payment-button.js +103 -0
  42. package/lib/module/components/payment-button.js.map +1 -0
  43. package/lib/module/components/payment-sheet.js +152 -0
  44. package/lib/module/components/payment-sheet.js.map +1 -0
  45. package/lib/module/components/views/status-view.js +105 -0
  46. package/lib/module/components/views/status-view.js.map +1 -0
  47. package/lib/module/components/views/transfer-view.js +157 -0
  48. package/lib/module/components/views/transfer-view.js.map +1 -0
  49. package/lib/module/components/views/verify-view.js +94 -0
  50. package/lib/module/components/views/verify-view.js.map +1 -0
  51. package/lib/module/hooks/use-countdown.js +21 -0
  52. package/lib/module/hooks/use-countdown.js.map +1 -0
  53. package/lib/module/index.js +4 -0
  54. package/lib/module/index.js.map +1 -0
  55. package/lib/module/internal/constants.js +37 -0
  56. package/lib/module/internal/constants.js.map +1 -0
  57. package/lib/module/internal/format.js +24 -0
  58. package/lib/module/internal/format.js.map +1 -0
  59. package/lib/module/internal/theme.js +21 -0
  60. package/lib/module/internal/theme.js.map +1 -0
  61. package/lib/module/package.json +1 -0
  62. package/lib/module/types.js +4 -0
  63. package/lib/module/types.js.map +1 -0
  64. package/lib/typescript/api/client.d.ts +17 -0
  65. package/lib/typescript/api/client.d.ts.map +1 -0
  66. package/lib/typescript/api/endpoints.d.ts +5 -0
  67. package/lib/typescript/api/endpoints.d.ts.map +1 -0
  68. package/lib/typescript/components/bottom-sheet.d.ts +18 -0
  69. package/lib/typescript/components/bottom-sheet.d.ts.map +1 -0
  70. package/lib/typescript/components/icons.d.ts +12 -0
  71. package/lib/typescript/components/icons.d.ts.map +1 -0
  72. package/lib/typescript/components/payment-button.d.ts +7 -0
  73. package/lib/typescript/components/payment-button.d.ts.map +1 -0
  74. package/lib/typescript/components/payment-sheet.d.ts +17 -0
  75. package/lib/typescript/components/payment-sheet.d.ts.map +1 -0
  76. package/lib/typescript/components/views/status-view.d.ts +12 -0
  77. package/lib/typescript/components/views/status-view.d.ts.map +1 -0
  78. package/lib/typescript/components/views/transfer-view.d.ts +13 -0
  79. package/lib/typescript/components/views/transfer-view.d.ts.map +1 -0
  80. package/lib/typescript/components/views/verify-view.d.ts +10 -0
  81. package/lib/typescript/components/views/verify-view.d.ts.map +1 -0
  82. package/lib/typescript/hooks/use-countdown.d.ts +8 -0
  83. package/lib/typescript/hooks/use-countdown.d.ts.map +1 -0
  84. package/lib/typescript/index.d.ts +3 -0
  85. package/lib/typescript/index.d.ts.map +1 -0
  86. package/lib/typescript/internal/constants.d.ts +20 -0
  87. package/lib/typescript/internal/constants.d.ts.map +1 -0
  88. package/lib/typescript/internal/format.d.ts +7 -0
  89. package/lib/typescript/internal/format.d.ts.map +1 -0
  90. package/lib/typescript/internal/theme.d.ts +13 -0
  91. package/lib/typescript/internal/theme.d.ts.map +1 -0
  92. package/lib/typescript/types.d.ts +67 -0
  93. package/lib/typescript/types.d.ts.map +1 -0
  94. package/package.json +70 -0
  95. package/src/api/client.ts +76 -0
  96. package/src/api/endpoints.ts +4 -0
  97. package/src/components/bottom-sheet.tsx +144 -0
  98. package/src/components/icons.tsx +90 -0
  99. package/src/components/payment-button.tsx +112 -0
  100. package/src/components/payment-sheet.tsx +149 -0
  101. package/src/components/views/status-view.tsx +61 -0
  102. package/src/components/views/transfer-view.tsx +112 -0
  103. package/src/components/views/verify-view.tsx +69 -0
  104. package/src/hooks/use-countdown.ts +20 -0
  105. package/src/index.ts +10 -0
  106. package/src/internal/constants.ts +34 -0
  107. package/src/internal/format.ts +21 -0
  108. package/src/internal/theme.ts +28 -0
  109. package/src/types.ts +73 -0
@@ -0,0 +1,69 @@
1
+ import { useState } from 'react';
2
+ import { StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
3
+ import type { ResolvedTheme } from '../../internal/theme';
4
+
5
+ interface VerifyViewProps {
6
+ theme: ResolvedTheme;
7
+ busy: boolean;
8
+ onSubmit: (trxHash: string) => void;
9
+ }
10
+
11
+ /** Step where the buyer pastes their transaction hash to confirm the transfer. */
12
+ export function VerifyView({ theme, busy, onSubmit }: VerifyViewProps) {
13
+ const [hash, setHash] = useState('');
14
+ const trimmed = hash.trim();
15
+ const disabled = !trimmed || busy;
16
+
17
+ return (
18
+ <View>
19
+ <Text style={styles.title}>Verify transaction</Text>
20
+ <Text style={styles.subtitle}>
21
+ Enter your transaction hash to confirm the payment.
22
+ </Text>
23
+
24
+ <Text style={styles.label}>
25
+ Hash <Text style={styles.req}>*</Text>
26
+ </Text>
27
+ <TextInput
28
+ style={styles.input}
29
+ placeholder='Enter your transaction hash'
30
+ placeholderTextColor='#9ca3af'
31
+ value={hash}
32
+ onChangeText={setHash}
33
+ autoCapitalize='none'
34
+ autoCorrect={false}
35
+ />
36
+
37
+ <TouchableOpacity
38
+ style={[
39
+ styles.primaryBtn,
40
+ { backgroundColor: disabled ? '#dff0f7' : theme.accent, borderRadius: theme.radius },
41
+ ]}
42
+ disabled={disabled}
43
+ onPress={() => onSubmit(trimmed)}
44
+ >
45
+ <Text style={[styles.primaryBtnText, { color: disabled ? '#9ca3af' : '#fff' }]}>
46
+ {busy ? 'Verifying…' : 'Confirm transaction'}
47
+ </Text>
48
+ </TouchableOpacity>
49
+ </View>
50
+ );
51
+ }
52
+
53
+ const styles = StyleSheet.create({
54
+ title: { fontSize: 16, fontWeight: '700', color: '#1e1e1e', textAlign: 'center' },
55
+ subtitle: { fontSize: 13, color: '#94a3b8', textAlign: 'center', marginTop: 4, marginBottom: 16 },
56
+ label: { fontSize: 14, fontWeight: '500', color: '#1e1e1e', marginBottom: 6 },
57
+ req: { color: '#fb7185' },
58
+ input: {
59
+ borderWidth: 1,
60
+ borderColor: '#d9d9d9',
61
+ borderRadius: 8,
62
+ padding: 12,
63
+ fontSize: 14,
64
+ color: '#1e1e1e',
65
+ marginBottom: 20,
66
+ },
67
+ primaryBtn: { width: '100%', paddingVertical: 15, alignItems: 'center' },
68
+ primaryBtnText: { fontSize: 16, fontWeight: '600' },
69
+ });
@@ -0,0 +1,20 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { formatTime } from '../internal/format';
3
+
4
+ /** A simple seconds countdown that stops at zero. */
5
+ export function useCountdown(seconds: number) {
6
+ const [timeLeft, setTimeLeft] = useState(seconds);
7
+
8
+ useEffect(() => {
9
+ if (timeLeft <= 0) return;
10
+ const id = setInterval(() => setTimeLeft((t) => t - 1), 1000);
11
+ return () => clearInterval(id);
12
+ }, [timeLeft]);
13
+
14
+ return {
15
+ timeLeft,
16
+ formatted: formatTime(timeLeft),
17
+ expired: timeLeft <= 0,
18
+ reset: () => setTimeLeft(seconds),
19
+ };
20
+ }
package/src/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ export { PaymentButton } from './components/payment-button';
2
+ export type {
3
+ PaymentButtonProps,
4
+ ClockPayAppearance,
5
+ ClockPayEnvironment,
6
+ CheckoutData,
7
+ CheckoutResponse,
8
+ VerifyCryptoPayload,
9
+ VerifyCryptoResponse,
10
+ } from './types';
@@ -0,0 +1,34 @@
1
+ /** API gateway for test keys (`cpay_test_pk_…`). */
2
+ export const TEST_API_BASE_URL = 'https://api.dev.theclockchain.io/api/v1';
3
+
4
+ /** API gateway for live keys (`cpay_live_pk_…`). */
5
+ export const LIVE_API_BASE_URL = 'https://api.theclockchain.io/api/v1';
6
+
7
+ /** ClockPay brand blue. */
8
+ export const DEFAULT_ACCENT = '#27AAE1';
9
+
10
+ /** How long the buyer has to complete a transfer, in seconds. */
11
+ export const COUNTDOWN_SECONDS = 300;
12
+
13
+ /**
14
+ * Picks the API gateway from the public key's environment prefix, unless an
15
+ * explicit `override` (the `apiBaseUrl` prop) is provided. Unknown prefixes fall
16
+ * back to the test gateway.
17
+ */
18
+ export function resolveApiBaseUrl(publicKey: string, override?: string): string {
19
+ if (override) return override;
20
+ if (publicKey.startsWith('cpay_live_pk_')) return LIVE_API_BASE_URL;
21
+ return TEST_API_BASE_URL;
22
+ }
23
+
24
+ /**
25
+ * Maps a coin's settlement network to its on-chain id, used when verifying a
26
+ * crypto transaction. Falls back to the `networkCode` from the checkout payload.
27
+ */
28
+ export const NETWORK_CODES: Record<string, string> = {
29
+ eth: '1',
30
+ optimism: '10',
31
+ bsc: '56',
32
+ polygon: '137',
33
+ tron: '10121',
34
+ };
@@ -0,0 +1,21 @@
1
+ import { NETWORK_CODES } from './constants';
2
+
3
+ /** Formats a number of seconds as `MM:SS`. */
4
+ export function formatTime(totalSeconds: number): string {
5
+ const safe = Math.max(0, totalSeconds);
6
+ const minutes = Math.floor(safe / 60);
7
+ const seconds = safe % 60;
8
+ return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
9
+ }
10
+
11
+ /** Resolves the on-chain code used to verify a transaction for a given checkout. */
12
+ export function resolveNetworkCode(network?: string, fallback?: string): string {
13
+ const key = network?.toLowerCase() ?? '';
14
+ return NETWORK_CODES[key] ?? fallback ?? '';
15
+ }
16
+
17
+ /** Truncates a long address for compact display: `0x1234…abcd`. */
18
+ export function truncateMiddle(value: string, lead = 10, tail = 8): string {
19
+ if (value.length <= lead + tail + 1) return value;
20
+ return `${value.slice(0, lead)}…${value.slice(-tail)}`;
21
+ }
@@ -0,0 +1,28 @@
1
+ import type { ClockPayAppearance } from '../types';
2
+ import { DEFAULT_ACCENT } from './constants';
3
+
4
+ /** Concrete colours/values resolved from an {@link ClockPayAppearance}. */
5
+ export interface ResolvedTheme {
6
+ accent: string;
7
+ radius: number;
8
+ buttonBg: string;
9
+ buttonFg: string;
10
+ buttonBorder: string;
11
+ fontFamily?: string;
12
+ }
13
+
14
+ /** Resolves an appearance object into concrete style values for the RN UI. */
15
+ export function resolveTheme(appearance?: ClockPayAppearance): ResolvedTheme {
16
+ const a = appearance ?? {};
17
+ const variant = a.variant ?? 'outline';
18
+ const accent = a.buttonColor ?? DEFAULT_ACCENT;
19
+
20
+ return {
21
+ accent: a.modalAccentColor ?? accent,
22
+ radius: a.borderRadius ?? 8,
23
+ buttonBg: variant === 'solid' ? accent : '#ffffff',
24
+ buttonFg: a.buttonTextColor ?? (variant === 'solid' ? '#ffffff' : accent),
25
+ buttonBorder: accent,
26
+ fontFamily: a.fontFamily,
27
+ };
28
+ }
package/src/types.ts ADDED
@@ -0,0 +1,73 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ /**
4
+ * Visual customization for the ClockPay button and bottom-sheet modal.
5
+ * Mirrors the web SDK's Stripe-style appearance API.
6
+ */
7
+ export interface ClockPayAppearance {
8
+ /** Button fill strategy. Defaults to `'outline'`. */
9
+ variant?: 'solid' | 'outline';
10
+ /** Primary brand colour. Defaults to `#27AAE1`. */
11
+ buttonColor?: string;
12
+ /** Overrides the button label colour. */
13
+ buttonTextColor?: string;
14
+ /** Corner radius for the button and primary actions. Defaults to `8`. */
15
+ borderRadius?: number;
16
+ /** Font family applied to SDK surfaces. */
17
+ fontFamily?: string;
18
+ /** Accent colour used inside the sheet (QR border, links, timer). Defaults to `buttonColor`. */
19
+ modalAccentColor?: string;
20
+ }
21
+
22
+ /** The environment a public key belongs to. */
23
+ export type ClockPayEnvironment = 'test' | 'live';
24
+
25
+ /** Payload returned by the checkout endpoint and rendered inside the sheet. */
26
+ export interface CheckoutData {
27
+ reference: string;
28
+ address: string;
29
+ network: string;
30
+ networkCode: string;
31
+ coin: string;
32
+ amount: number;
33
+ contractAddress: string;
34
+ }
35
+
36
+ export interface CheckoutResponse {
37
+ message: string;
38
+ data: CheckoutData;
39
+ }
40
+
41
+ export interface VerifyCryptoPayload {
42
+ reference: string;
43
+ trxHash: string;
44
+ code: string;
45
+ }
46
+
47
+ export interface VerifyCryptoResponse {
48
+ message: string;
49
+ }
50
+
51
+ /** Props for the public {@link PaymentButton} component. */
52
+ export interface PaymentButtonProps {
53
+ /** Public key from the business developer dashboard (e.g. `cpay_test_pk_...`). Required. */
54
+ publicKey: string;
55
+ /** Client secret returned from your server-side checkout call. Required. */
56
+ clientSecret: string;
57
+ /** Visual customization for the button and sheet. */
58
+ appearance?: ClockPayAppearance;
59
+ /** Button label. Defaults to "Pay with Clockpay". */
60
+ label?: ReactNode;
61
+ /** Disables the button. */
62
+ disabled?: boolean;
63
+ /** Override the API base URL. Defaults to the gateway matching the key prefix. */
64
+ apiBaseUrl?: string;
65
+ /** URL to open (via Linking) after a successful payment. Optional. */
66
+ redirectUrl?: string;
67
+ /** Called once the payment is confirmed on-chain. */
68
+ onSuccess?: (data: VerifyCryptoResponse) => void;
69
+ /** Called when initiating or verifying the payment fails. */
70
+ onError?: (error: Error) => void;
71
+ /** Called whenever the sheet closes, regardless of outcome. */
72
+ onClose?: () => void;
73
+ }