react-native-fpay 0.3.13 → 0.3.16

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 (34) hide show
  1. package/lib/module/FountainPayProvider.js +2 -2
  2. package/lib/module/FountainPayProvider.js.map +1 -1
  3. package/lib/module/core/api/client.js +1 -1
  4. package/lib/module/core/api/index.js +3 -3
  5. package/lib/module/core/api/index.js.map +1 -1
  6. package/lib/module/ui/modals/FPPaymentRequestModal.js +0 -1
  7. package/lib/module/ui/modals/FPPaymentRequestModal.js.map +1 -1
  8. package/lib/module/ui/modals/FPShell.js +0 -1
  9. package/lib/module/ui/modals/FPShell.js.map +1 -1
  10. package/lib/module/ui/screens/ResultScreen.js +321 -0
  11. package/lib/module/ui/screens/ResultScreen.js.map +1 -0
  12. package/lib/module/ui/screens/SendScreen.js +30 -134
  13. package/lib/module/ui/screens/SendScreen.js.map +1 -1
  14. package/lib/module/ui/theme/index.js +1 -1
  15. package/lib/typescript/src/core/api/index.d.ts +6 -2
  16. package/lib/typescript/src/core/api/index.d.ts.map +1 -1
  17. package/lib/typescript/src/ui/components/OtpInput/Styles.d.ts +21 -21
  18. package/lib/typescript/src/ui/modals/FPPaymentRequestModal.d.ts.map +1 -1
  19. package/lib/typescript/src/ui/modals/FPShell.d.ts.map +1 -1
  20. package/lib/typescript/src/ui/screens/ResultScreen.d.ts +8 -0
  21. package/lib/typescript/src/ui/screens/ResultScreen.d.ts.map +1 -0
  22. package/lib/typescript/src/ui/screens/SendScreen.d.ts.map +1 -1
  23. package/lib/typescript/src/ui/screens/styles.d.ts +82 -82
  24. package/lib/typescript/src/ui/screens/sub/sendPayment/BluetoothSubScreen.d.ts +22 -22
  25. package/lib/typescript/src/ui/screens/sub/sendPayment/ProximitySubScreen.d.ts +22 -22
  26. package/package.json +1 -1
  27. package/src/FountainPayProvider.tsx +2 -2
  28. package/src/core/api/client.ts +1 -1
  29. package/src/core/api/index.ts +3 -3
  30. package/src/ui/modals/FPPaymentRequestModal.tsx +1 -5
  31. package/src/ui/modals/FPShell.tsx +1 -6
  32. package/src/ui/screens/ResultScreen.tsx +291 -0
  33. package/src/ui/screens/SendScreen.tsx +37 -173
  34. package/src/ui/theme/index.ts +1 -1
@@ -0,0 +1,291 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ import { Animated, Easing, TouchableOpacity } from 'react-native';
3
+ import Svg, { Path, Circle } from 'react-native-svg';
4
+ import styled from 'styled-components/native';
5
+ import { C, F, R, S } from '../theme';
6
+ import type { FPTransaction } from '../../core/types';
7
+ import { transferAPI } from '../../core/api';
8
+
9
+ // ── Icons ─────────────────────────────────────────────────────
10
+
11
+ const SuccessIcon = () => (
12
+ <Svg width={64} height={64} viewBox="0 0 64 64" fill="none">
13
+ <Circle cx="32" cy="32" r="32" fill="#00875A" />
14
+ <Path d="M20 33L28 41L44 24" stroke="#fff" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round" />
15
+ </Svg>
16
+ );
17
+
18
+ const FailedIcon = () => (
19
+ <Svg width={64} height={64} viewBox="0 0 64 64" fill="none">
20
+ <Circle cx="32" cy="32" r="32" fill="#DE350B" />
21
+ <Path d="M22 22L42 42M42 22L22 42" stroke="#fff" strokeWidth="3.5" strokeLinecap="round" />
22
+ </Svg>
23
+ );
24
+
25
+ // ── Styled Components ─────────────────────────────────────────
26
+
27
+ const Container = styled(Animated.View)`
28
+ flex: 1;
29
+ background-color: ${C.white};
30
+ padding: ${S.xxl}px ${S.lg}px ${S.xl}px;
31
+ align-items: center;
32
+ `;
33
+
34
+ const IconWrap = styled(Animated.View)`
35
+ margin-bottom: ${S.lg}px;
36
+ `;
37
+
38
+ const IconBg = styled.View<{ bg: string }>`
39
+ width: 112px;
40
+ height: 112px;
41
+ border-radius: 56px;
42
+ justify-content: center;
43
+ align-items: center;
44
+ background-color: ${({ bg }) => bg};
45
+ `;
46
+
47
+ const StatusText = styled.Text<{ color: string }>`
48
+ font-size: ${F.xl}px;
49
+ font-weight: 800;
50
+ margin-bottom: ${S.sm}px;
51
+ text-align: center;
52
+ color: ${({ color }) => color};
53
+ `;
54
+
55
+ const Amount = styled.Text`
56
+ font-size: ${F.hero}px;
57
+ font-weight: 900;
58
+ color: ${C.ink};
59
+ margin-bottom: ${S.xl}px;
60
+ letter-spacing: -1px;
61
+ `;
62
+
63
+ const Card = styled.View`
64
+ width: 100%;
65
+ background-color: ${C.surface};
66
+ border-radius: ${R.xl}px;
67
+ padding: ${S.md}px ${S.lg}px;
68
+ margin-bottom: ${S.xl}px;
69
+ `;
70
+
71
+ const RowWrap = styled.View`
72
+ flex-direction: row;
73
+ justify-content: space-between;
74
+ align-items: center;
75
+ padding: ${S.sm}px 0;
76
+ border-bottom-width: 1px;
77
+ border-bottom-color: ${C.border};
78
+ `;
79
+
80
+ const RowLabel = styled.Text`
81
+ font-size: ${F.sm}px;
82
+ color: ${C.muted};
83
+ font-weight: 500;
84
+ `;
85
+
86
+ const RowValue = styled.Text`
87
+ font-size: ${F.sm}px;
88
+ color: ${C.ink};
89
+ font-weight: 700;
90
+ max-width: 60%;
91
+ text-align: right;
92
+ `;
93
+
94
+ const Footer = styled.View`
95
+ flex-direction: row;
96
+ align-items: center;
97
+ margin-top: auto;
98
+ `;
99
+
100
+ const CloseBtn = styled(TouchableOpacity)`
101
+ flex: 1;
102
+ background-color: ${C.brand};
103
+ border-radius: ${R.full}px;
104
+ padding: ${S.md}px 0;
105
+ align-items: center;
106
+ margin-left: ${S.md}px;
107
+ `;
108
+
109
+ const CloseBtnText = styled.Text`
110
+ color: ${C.white};
111
+ font-weight: 800;
112
+ font-size: ${F.md}px;
113
+ `;
114
+
115
+ const RingWrap = styled.View`
116
+ width: 48px;
117
+ height: 48px;
118
+ justify-content: center;
119
+ align-items: center;
120
+ `;
121
+
122
+ const RingLabel = styled.Text`
123
+ position: absolute;
124
+ font-size: 8px;
125
+ color: ${C.muted};
126
+ text-align: center;
127
+ font-weight: 600;
128
+ `;
129
+
130
+ // ── Countdown ────────────────────────────────────────────────
131
+
132
+ const COUNTDOWN_SECONDS = 5;
133
+ const RING_SIZE = 48;
134
+ const STROKE_WIDTH = 3;
135
+ const RADIUS = (RING_SIZE - STROKE_WIDTH) / 2;
136
+ const CIRCUMFERENCE = 2 * Math.PI * RADIUS;
137
+
138
+ const AnimatedCircle = Animated.createAnimatedComponent(Circle);
139
+
140
+ function CountdownRing({ duration }: { duration: number }) {
141
+ const progress = useRef(new Animated.Value(0)).current;
142
+
143
+ useEffect(() => {
144
+ Animated.timing(progress, {
145
+ toValue: 1,
146
+ duration,
147
+ easing: Easing.linear,
148
+ useNativeDriver: false,
149
+ }).start();
150
+ }, [duration, progress]);
151
+
152
+ const strokeDashoffset = progress.interpolate({
153
+ inputRange: [0, 1],
154
+ outputRange: [0, CIRCUMFERENCE],
155
+ });
156
+
157
+ return (
158
+ <RingWrap>
159
+ <Svg width={RING_SIZE} height={RING_SIZE}>
160
+ <Circle
161
+ cx={RING_SIZE / 2}
162
+ cy={RING_SIZE / 2}
163
+ r={RADIUS}
164
+ stroke={C.border}
165
+ strokeWidth={STROKE_WIDTH}
166
+ fill="none"
167
+ />
168
+ <AnimatedCircle
169
+ cx={RING_SIZE / 2}
170
+ cy={RING_SIZE / 2}
171
+ r={RADIUS}
172
+ stroke={C.brand}
173
+ strokeWidth={STROKE_WIDTH}
174
+ fill="none"
175
+ strokeDasharray={`${CIRCUMFERENCE} ${CIRCUMFERENCE}`}
176
+ strokeDashoffset={strokeDashoffset}
177
+ strokeLinecap="round"
178
+ rotation="-90"
179
+ origin={`${RING_SIZE / 2}, ${RING_SIZE / 2}`}
180
+ />
181
+ </Svg>
182
+ <RingLabel>{`Auto\nclose`}</RingLabel>
183
+ </RingWrap>
184
+ );
185
+ }
186
+
187
+ // ── Row ──────────────────────────────────────────────────────
188
+
189
+ function Row({ label, value }: { label: string; value: string }) {
190
+ return (
191
+ <RowWrap>
192
+ <RowLabel>{label}</RowLabel>
193
+ <RowValue>{value}</RowValue>
194
+ </RowWrap>
195
+ );
196
+ }
197
+
198
+ // ── Main ─────────────────────────────────────────────────────
199
+
200
+ interface Props {
201
+ transaction: FPTransaction | any;
202
+ onClose: () => void;
203
+ }
204
+
205
+ export function ResultScreen({ transaction, onClose }: Props) {
206
+ const [transactionDetail, setTransactionDetail] = useState<any>(null)
207
+ const slideAnim = useRef(new Animated.Value(60)).current;
208
+ const opacAnim = useRef(new Animated.Value(0)).current;
209
+ const scaleAnim = useRef(new Animated.Value(0.5)).current;
210
+
211
+ const isSuccess = transactionDetail?.status.toLowerCase() === 'successful';
212
+ const accentColor = isSuccess ? C.green : C.red;
213
+ const bgColor = isSuccess ? '#E3FCEF' : '#FFEBE6';
214
+
215
+ const formatted = `${transactionDetail?.currency || 'NGN'} ${Number(transactionDetail?.amount).toLocaleString('en-NG', {
216
+ minimumFractionDigits: 2,
217
+ })}`;
218
+
219
+ const recipient = transaction?.recipient as any;
220
+ const recipientName = recipient?.accountName ?? recipient?.name ?? '—';
221
+
222
+ const channelLabel: Record<string, string> = {
223
+ transfer: 'Bank Transfer',
224
+ bluetooth: 'Bluetooth',
225
+ proximity: 'Nearby',
226
+ nqr: 'QR Code',
227
+ nfc: 'NFC Tap',
228
+ };
229
+
230
+ const dateStr = transactionDetail?.createdAt
231
+ ? new Date(transactionDetail?.createdAt).toLocaleString('en-NG')
232
+ : '—';
233
+
234
+ const loadTransaction = async()=>{
235
+ const response = await transferAPI.status(transaction.reference) as any;
236
+ console.log("Transaction payload: ", response);
237
+ if(response.status){
238
+ setTransactionDetail(response.payload);
239
+ }
240
+ }
241
+
242
+ useEffect(() => {
243
+ Animated.parallel([
244
+ Animated.spring(scaleAnim, { toValue: 1, useNativeDriver: true }),
245
+ Animated.timing(opacAnim, { toValue: 1, duration: 300, useNativeDriver: true }),
246
+ Animated.timing(slideAnim, { toValue: 0, duration: 350, useNativeDriver: true }),
247
+ ]).start();
248
+ }, [scaleAnim, opacAnim, slideAnim]);
249
+
250
+ useEffect(() => {
251
+ const timer = setTimeout(onClose, COUNTDOWN_SECONDS * 1000);
252
+ return () => clearTimeout(timer);
253
+ }, [onClose]);
254
+
255
+ useEffect(()=>{
256
+ if(transaction){
257
+ loadTransaction();
258
+ }
259
+ }, [transaction])
260
+
261
+ return (
262
+ <Container style={{ opacity: opacAnim, transform: [{ translateY: slideAnim }] }}>
263
+ <IconWrap style={{ transform: [{ scale: scaleAnim }] }}>
264
+ <IconBg bg={bgColor}>
265
+ {isSuccess ? <SuccessIcon /> : <FailedIcon />}
266
+ </IconBg>
267
+ </IconWrap>
268
+
269
+ <StatusText color={accentColor}>
270
+ {isSuccess ? 'Payment Successful' : 'Payment Failed'}
271
+ </StatusText>
272
+
273
+ <Amount>{formatted}</Amount>
274
+
275
+ <Card>
276
+ <Row label="To" value={recipientName} />
277
+ <Row label="Channel" value={channelLabel[transactionDetail?.channel] ?? transaction?.channel} />
278
+ <Row label="Reference" value={transactionDetail?.reference} />
279
+ <Row label="Date" value={dateStr} />
280
+ <Row label="Status" value={transactionDetail?.status?.toUpperCase()} />
281
+ </Card>
282
+
283
+ <Footer>
284
+ <CountdownRing duration={COUNTDOWN_SECONDS * 1000} />
285
+ <CloseBtn onPress={loadTransaction} activeOpacity={0.8}>
286
+ <CloseBtnText>Close</CloseBtnText>
287
+ </CloseBtn>
288
+ </Footer>
289
+ </Container>
290
+ );
291
+ }
@@ -3,18 +3,14 @@
3
3
  // Shows channel selection, then opens the
4
4
  // relevant sub-screen in the same modal sheet
5
5
  // ─────────────────────────────────────────────
6
- import React, { useState } from 'react';
6
+ import { useState } from 'react';
7
7
  import {
8
8
  View,
9
9
  Text,
10
10
  TouchableOpacity,
11
- StyleSheet,
12
11
  ScrollView,
13
12
  Dimensions,
14
- TextInput,
15
13
  } from 'react-native';
16
- import { C, R, S, F, shadow } from '../theme';
17
- import { FPButton } from '../components/FPButton';
18
14
  import { TransferSubScreen } from './sub/sendPayment/TransferSubScreen';
19
15
  import { NQRSubScreen } from './sub/sendPayment/NQRSubScreen';
20
16
  import { ProximitySubScreen } from './sub/sendPayment/ProximitySubScreen';
@@ -29,27 +25,17 @@ import type {
29
25
  FPUserInfo,
30
26
  FPTransferRecipient,
31
27
  FPSendWalletPaymentRequest,
32
- FPTransactionResponse,
33
28
  } from '../../core/types';
34
29
  import styled from 'styled-components/native';
35
30
  import Ionicons from 'react-native-vector-icons/Ionicons';
36
31
  import Svg, { Path } from 'react-native-svg';
37
32
  import { nfcAPI, nqrAPI, transferAPI } from '../../core/api';
38
- import {
39
- ButtonContainer,
40
- ContentContainer,
41
- CTAButton,
42
- CTAText,
43
- InputBox,
44
- InputContainer,
45
- StyledTextInput,
46
- } from './styles';
47
- import OTPInputs from '../components/OtpInput';
48
33
  import ConfirmScreen from '../components/ConfirmScreen';
49
34
  import LoadingAnimation from '../components/LoadingAnimation';
50
35
  import { getFPStore } from '../../store/FPStore';
36
+ import { ResultScreen } from './ResultScreen';
51
37
 
52
- const { width, height } = Dimensions.get('window');
38
+ const { height } = Dimensions.get('window');
53
39
 
54
40
  type Channel = 'TRANSFER' | 'QRCODE' | 'NFC' | 'BTH' | 'PXTR';
55
41
 
@@ -150,143 +136,6 @@ const ActionLabel = styled(Text)`
150
136
  line-height: 14px;
151
137
  `;
152
138
 
153
- const SearchContainer = styled(View)`
154
- flex-direction: row;
155
- align-items: center;
156
- background-color: #f9fafb;
157
- border-radius: 12px;
158
- padding: 14px 16px;
159
- margin-bottom: 24px;
160
- border: 1px solid #e5e7eb;
161
- `;
162
-
163
- const SearchInput = styled(TextInput)`
164
- flex: 1;
165
- margin-left: 10px;
166
- font-size: 14px;
167
- color: #1f2937;
168
- padding: 0;
169
- `;
170
-
171
- const AddContactButton = styled.TouchableOpacity`
172
- align-items: center;
173
- margin-right: 20px;
174
-
175
- flex-direction: row;
176
- gap: 20px;
177
- `;
178
-
179
- const Icon = styled(Text)<{ size?: number; color?: string }>`
180
- font-size: ${(props) => props.size || 24}px;
181
- color: ${(props) => props.color || '#000000'};
182
- `;
183
-
184
- const AddCircle = styled.View`
185
- width: 44px;
186
- height: 44px;
187
- border-radius: 32px;
188
- background-color: #fff;
189
- border-width: 2px;
190
- border-color: #e0e0e0;
191
- border-style: dashed;
192
- justify-content: center;
193
- align-items: center;
194
- margin-bottom: 8px;
195
- `;
196
-
197
- const PrxyIconContainer = styled(View)<{ color: string }>`
198
- width: 44px;
199
- height: 44px;
200
- border-radius: 100%;
201
- background-color: ${(props) => props.color};
202
- justify-content: center;
203
- align-items: center;
204
- elevation: 3;
205
- shadow-color: #000;
206
- shadow-offset: 0px 2px;
207
- shadow-opacity: 0.12;
208
- shadow-radius: 4px;
209
- `;
210
-
211
- const ContactName = styled.Text`
212
- font-size: 12px;
213
- color: #000;
214
- `;
215
-
216
- const ScanIcon = ({ color = '#111', size = 22 }) => (
217
- <Svg
218
- width={size}
219
- height={size}
220
- strokeWidth="0.9"
221
- viewBox="0 0 24 24"
222
- fill="none"
223
- color={color}
224
- >
225
- <Path
226
- d="M6 3H3V6"
227
- stroke="#000000"
228
- strokeWidth="0.9"
229
- strokeLinecap="round"
230
- strokeLinejoin="round"
231
- />
232
- <Path
233
- d="M2 12H12L22 12"
234
- stroke="#000000"
235
- strokeWidth="0.9"
236
- strokeLinecap="round"
237
- strokeLinejoin="round"
238
- />
239
- <Path
240
- d="M9 19V17V15"
241
- stroke="#000000"
242
- strokeWidth="0.9"
243
- strokeLinecap="round"
244
- strokeLinejoin="round"
245
- />
246
- <Path
247
- d="M12 16V15.5V15"
248
- stroke="#000000"
249
- strokeWidth="0.9"
250
- strokeLinecap="round"
251
- strokeLinejoin="round"
252
- />
253
- <Path
254
- d="M15 17V16V15"
255
- stroke="#000000"
256
- strokeWidth="0.9"
257
- strokeLinecap="round"
258
- strokeLinejoin="round"
259
- />
260
- <Path
261
- d="M12 21V19.5V18"
262
- stroke="#000000"
263
- strokeWidth="0.9"
264
- strokeLinecap="round"
265
- strokeLinejoin="round"
266
- />
267
- <Path
268
- d="M18 3H21V6"
269
- stroke="#000000"
270
- strokeWidth="0.9"
271
- strokeLinecap="round"
272
- strokeLinejoin="round"
273
- />
274
- <Path
275
- d="M6 21H3V18"
276
- stroke="#000000"
277
- strokeWidth="0.9"
278
- strokeLinecap="round"
279
- strokeLinejoin="round"
280
- />
281
- <Path
282
- d="M18 21H21V18"
283
- stroke="#000000"
284
- strokeWidth="0.9"
285
- strokeLinecap="round"
286
- strokeLinejoin="round"
287
- />
288
- </Svg>
289
- );
290
139
 
291
140
  const BluetoothIcon = ({ color = '#111', size = 22 }) => (
292
141
  <Svg
@@ -464,15 +313,11 @@ const SendScreen = ({
464
313
  onError,
465
314
  }: Props) => {
466
315
  const [channel, setChannel] = useState<Channel>('TRANSFER');
467
- const [transactionAmount, setTransactionAmount] = useState<string>('');
468
316
  const [loading, setLoading] = useState<boolean>(false);
469
- const [showAmountModal, setShowAmountModal] = useState<boolean>(false);
470
- const [showConfirmationModal, setShowConfirmationModal] =
471
- useState<boolean>(false);
317
+ const [showConfirmationModal, setShowConfirmationModal] = useState<boolean>(false);
318
+ const [completedTx, setCompletedTx] = useState<FPTransaction | null>(null);
472
319
 
473
- const [transactionPayload, setTransactionPayload] = useState<
474
- FPSendPaymentRequest | FPSendWalletPaymentRequest
475
- >({} as FPSendPaymentRequest | FPSendWalletPaymentRequest);
320
+ const [transactionPayload, setTransactionPayload] = useState< FPSendPaymentRequest | FPSendWalletPaymentRequest>({} as FPSendPaymentRequest | FPSendWalletPaymentRequest);
476
321
 
477
322
  const formatted = `${currency} ${amount.toLocaleString('en-NG', { minimumFractionDigits: 2 })}`;
478
323
 
@@ -488,26 +333,31 @@ const SendScreen = ({
488
333
  setShowConfirmationModal(true);
489
334
  };
490
335
 
336
+ const handleResultClose = () => {
337
+ setCompletedTx(null);
338
+ onClose(); // close the entire shell
339
+ };
340
+
491
341
  const handleProcessingTransaction = async (temptId: string) => {
492
342
  console.log('Got in here for processing');
493
343
  try {
494
344
  setLoading(true);
495
345
  setShowConfirmationModal(false);
496
- let response: FPTransactionResponse | null = null;
346
+ let response: any = null;
497
347
  switch (transactionPayload?.channel) {
498
348
  case 'transfer':
499
349
  case 'bluetooth':
500
350
  case 'proximity':
501
351
  if ('isBank' in transactionPayload && transactionPayload.isBank) {
502
- response = await transferAPI.sendToBank(
352
+ response = (await transferAPI.sendToBank(
503
353
  transactionPayload as FPSendPaymentRequest,
504
354
  temptId
505
- );
355
+ )) || null;
506
356
  } else {
507
- response = await transferAPI.sendToWallet(
357
+ response = (await transferAPI.sendToWallet(
508
358
  transactionPayload as FPSendWalletPaymentRequest,
509
359
  temptId
510
- );
360
+ )) || null;
511
361
  }
512
362
  break;
513
363
  case 'nqr':
@@ -534,15 +384,19 @@ const SendScreen = ({
534
384
  onError?.({ message: 'Invalid channel' } as FPError);
535
385
  break;
536
386
  }
537
-
538
- if (response?.status) {
539
- onError?.({
540
- message: response?.message || 'Transaction failed',
541
- } as FPError);
542
- return;
387
+
388
+ if (!response?.status) {
389
+ // Show failed result screen
390
+ setCompletedTx({
391
+ ...(response?.payload ?? {}),
392
+ status: 'failed',
393
+ } as FPTransaction);
394
+ return; // ← don't call onError — let result screen handle it
543
395
  }
544
396
 
545
- onPaymentSent?.(response?.payload as FPTransaction);
397
+ // Success — show result screen, notify host app
398
+ setCompletedTx(response.payload as FPTransaction);
399
+ onPaymentSent?.(response.payload as FPTransaction);
546
400
  } catch (error) {
547
401
  onError?.(error as FPError);
548
402
  } finally {
@@ -550,6 +404,16 @@ const SendScreen = ({
550
404
  }
551
405
  };
552
406
 
407
+ if (completedTx) {
408
+ console.log("Completed Tx: ", completedTx)
409
+ return (
410
+ <ResultScreen
411
+ transaction={{...transactionPayload, ...completedTx}}
412
+ onClose={handleResultClose}
413
+ />
414
+ );
415
+ }
416
+
553
417
  return (
554
418
  <Container>
555
419
  {loading && <LoadingAnimation />}
@@ -1,6 +1,6 @@
1
1
  export const C = {
2
2
  ink: '#0B1D35',
3
- brand: '#0052CC',
3
+ brand: '#003333',
4
4
  brandLight: '#E8F0FE',
5
5
  green: '#00875A',
6
6
  greenLight: '#E3FCEF',