@fadyshawky/react-native-magic 2.0.4 → 2.0.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 (110) hide show
  1. package/package.json +1 -1
  2. package/template/src/common/ImageResources.g.ts +33 -1
  3. package/template/src/common/components/Background.tsx +3 -1
  4. package/template/src/common/components/Container.tsx +1 -1
  5. package/template/src/common/components/OTPInput.tsx +3 -2
  6. package/template/src/common/components/PrimaryButton.tsx +23 -23
  7. package/template/src/common/components/PrimaryTextInput.tsx +189 -199
  8. package/template/src/common/components/RadioIcon.tsx +4 -4
  9. package/template/src/common/components/SafeText.tsx +41 -0
  10. package/template/src/common/components/SearchBar.tsx +19 -17
  11. package/template/src/common/components/TryAgain.tsx +3 -3
  12. package/template/src/common/localization/localization.ts +10 -0
  13. package/template/src/common/localization/translations/commonLocalization.ts +97 -0
  14. package/template/src/common/localization/translations/homeLocalization.ts +24 -0
  15. package/template/src/common/localization/translations/loginLocalization.ts +28 -2
  16. package/template/src/common/localization/translations/mainNavigationLocalization.ts +30 -0
  17. package/template/src/common/localization/translations/navigationLocalization.ts +48 -0
  18. package/template/src/common/localization/translations/otpLocalization.ts +28 -0
  19. package/template/src/common/localization/translations/passwordLocalization.ts +54 -0
  20. package/template/src/common/localization/translations/posLocalization.ts +196 -0
  21. package/template/src/common/utils/FeesCaalculation.tsx +37 -0
  22. package/template/src/common/utils/index.tsx +11 -0
  23. package/template/src/common/utils/printData.tsx +161 -0
  24. package/template/src/common/validations/errorValidations.ts +3 -2
  25. package/template/src/components/PrinterExample.js +226 -0
  26. package/template/src/core/api/serverHeaders.ts +62 -1
  27. package/template/src/core/store/Categories/categoryActions.ts +33 -0
  28. package/template/src/core/store/Categories/categorySlice.ts +75 -0
  29. package/template/src/core/store/Categories/categoryState.ts +41 -0
  30. package/template/src/core/store/Providers/providersActions.ts +102 -0
  31. package/template/src/core/store/Providers/providersSlice.ts +136 -0
  32. package/template/src/core/store/Providers/providersState.ts +37 -0
  33. package/template/src/core/store/Services/servicesActions.ts +191 -0
  34. package/template/src/core/store/Services/servicesSlice.ts +205 -0
  35. package/template/src/core/store/Services/servicesState.ts +466 -0
  36. package/template/src/core/store/app/appSlice.ts +13 -5
  37. package/template/src/core/store/app/appState.ts +10 -2
  38. package/template/src/core/store/rootReducer.ts +6 -1
  39. package/template/src/core/store/store.tsx +55 -2
  40. package/template/src/core/store/user/userActions.ts +164 -26
  41. package/template/src/core/store/user/userSlice.ts +193 -21
  42. package/template/src/core/store/user/userState.ts +148 -25
  43. package/template/src/core/theme/colors.ts +70 -94
  44. package/template/src/core/theme/commonConsts.ts +1 -1
  45. package/template/src/core/theme/commonSizes.ts +94 -119
  46. package/template/src/core/theme/commonStyles.ts +22 -22
  47. package/template/src/core/theme/fonts.ts +14 -13
  48. package/template/src/core/theme/themes.ts +75 -386
  49. package/template/src/core/theme/types.ts +15 -201
  50. package/template/src/core/utils/stringUtils.ts +114 -0
  51. package/template/src/modules/SunmiCard.js +212 -0
  52. package/template/src/modules/SunmiPrepaid.ts +122 -0
  53. package/template/src/navigation/AuthStack.tsx +8 -0
  54. package/template/src/navigation/HeaderComponents.tsx +76 -1
  55. package/template/src/navigation/MainNavigation.tsx +3 -1
  56. package/template/src/navigation/MainStack.tsx +130 -56
  57. package/template/src/navigation/TabBar.tsx +111 -59
  58. package/template/src/navigation/types.ts +24 -0
  59. package/template/src/screens/Categories/Categories.tsx +141 -0
  60. package/template/src/screens/Categories/hooks/useCategoriesData.ts +33 -0
  61. package/template/src/screens/Categories/types.ts +7 -0
  62. package/template/src/screens/Favorites/Favorites.tsx +130 -0
  63. package/template/src/screens/ForceChangePassword/ForceChangePasswordScreen.tsx +155 -0
  64. package/template/src/screens/History/History.tsx +430 -0
  65. package/template/src/screens/History/hooks/useHistoryData.ts +49 -0
  66. package/template/src/screens/History/types.ts +7 -0
  67. package/template/src/screens/InquiredBill/InquiredBill.tsx +443 -0
  68. package/template/src/screens/InquiredBill/hooks/useInquiredData.ts +91 -0
  69. package/template/src/screens/Login/Login.tsx +85 -85
  70. package/template/src/screens/OTP/OTPScreen.tsx +170 -0
  71. package/template/src/screens/PaymentConfirmation/PaymentConfirmation.tsx +326 -0
  72. package/template/src/screens/Providers/Providers.tsx +166 -0
  73. package/template/src/screens/Providers/hooks/useProvidersData.ts +33 -0
  74. package/template/src/screens/Providers/types.ts +7 -0
  75. package/template/src/screens/ReceiptScreen/ReceiptScreen.tsx +181 -0
  76. package/template/src/screens/ReceiptScreen/hooks/useReceiptData.ts +46 -0
  77. package/template/src/screens/ReceiptScreen/utils/utils.tsx +156 -0
  78. package/template/src/screens/Services/Services.tsx +144 -0
  79. package/template/src/screens/Services/hooks/useServicesData.ts +41 -0
  80. package/template/src/screens/SingleService/Components/FawryInputs.tsx +446 -0
  81. package/template/src/screens/SingleService/SingleService.tsx +229 -0
  82. package/template/src/screens/SingleService/hooks/useServiceData.ts +164 -0
  83. package/template/src/screens/home/Components/PayByCode.tsx +129 -0
  84. package/template/src/screens/home/HomeScreen.tsx +268 -77
  85. package/template/src/screens/home/hooks/useHomeData.ts +32 -38
  86. package/template/src/screens/index.tsx +24 -0
  87. package/template/src/screens/profile/Profile.tsx +290 -2
  88. package/template/src/services/SunmiPrinterInternal.js +268 -0
  89. package/template/src/types/sunmiPrepaid.d.ts +20 -0
  90. package/template/src/utils/SunmiPrinter.ts +442 -0
  91. package/template/src/utils/feesCalculator.ts +92 -0
  92. package/template/src/common/components/Stepper.tsx +0 -153
  93. package/template/src/common/components/Svg.tsx +0 -25
  94. package/template/src/common/hooks/useDebounce.ts +0 -17
  95. package/template/src/common/hooks/usePrevious.ts +0 -11
  96. package/template/src/common/localization/intlFormatter.ts +0 -37
  97. package/template/src/common/urls/emailUrl.ts +0 -20
  98. package/template/src/common/urls/mapUrl.ts +0 -22
  99. package/template/src/common/utils/listHandlers.ts +0 -30
  100. package/template/src/common/utils/serializeQueryParams.ts +0 -10
  101. package/template/src/common/validations/hooks/useDatesError.ts +0 -40
  102. package/template/src/common/validations/profileValidations.ts +0 -30
  103. package/template/src/core/theme/shadows.ts +0 -135
  104. package/template/src/navigation/TopTabBar.tsx +0 -77
  105. package/template/src/screens/Settings/Settings.tsx +0 -5
  106. package/template/src/screens/home/components/CarouselSection.tsx +0 -79
  107. package/template/src/screens/home/components/FeaturedCarousel.tsx +0 -128
  108. package/template/src/screens/main/Main.tsx +0 -5
  109. package/template/src/screens/registration/RegistrationScreen.tsx +0 -198
  110. package/template/src/screens/resetPassword/ForgotPasswordScreen.tsx +0 -129
@@ -0,0 +1,326 @@
1
+ import {
2
+ RouteProp,
3
+ useIsFocused,
4
+ useNavigation,
5
+ useRoute,
6
+ } from '@react-navigation/native';
7
+ import {NativeStackNavigationProp} from '@react-navigation/native-stack';
8
+ import React, {useEffect, useState} from 'react';
9
+ import {
10
+ Alert,
11
+ Image,
12
+ ImageResizeMode,
13
+ ImageStyle,
14
+ ScrollView,
15
+ StyleSheet,
16
+ TextStyle,
17
+ ViewStyle,
18
+ } from 'react-native';
19
+ import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
20
+ import {ButtonType} from '../../../types';
21
+ import {Container} from '../../common/components/Container';
22
+ import {PrimaryButton} from '../../common/components/PrimaryButton';
23
+ import {RTLAwareText} from '../../common/components/RTLAwareText';
24
+ import {ImageResources} from '../../common/ImageResources.g';
25
+ import {useTranslation} from '../../common/localization/LocalizationProvider';
26
+ import {useAppDispatch, useAppSelector} from '../../core/store/reduxHelpers';
27
+ import {RootState} from '../../core/store/rootReducer';
28
+ import {
29
+ payService,
30
+ reverseService,
31
+ } from '../../core/store/Services/servicesActions';
32
+ import {CommonSizes} from '../../core/theme/commonSizes';
33
+ import {scaleHeight} from '../../core/theme/scaling';
34
+ import {useTheme} from '../../core/theme/ThemeProvider';
35
+ import {Theme} from '../../core/theme/types';
36
+ import {HeaderBack, HeaderButton} from '../../navigation/HeaderComponents';
37
+ import {RootStackParamList} from '../../navigation/types';
38
+ import {omit} from 'lodash';
39
+ import {calculateFees, makePrintData} from '../../common/utils';
40
+ import {normalizeAndTrimWhitespace} from '../../common/helpers/stringsHelpers';
41
+ import {decryptTripleDES} from '../../core/utils/stringUtils';
42
+ import {RTLAwareView} from '../../common/components/RTLAwareView';
43
+ import {SkypeIndicator} from 'react-native-indicators';
44
+ import {createThemedStyles} from '../../core/theme/commonStyles';
45
+ import {getLabel} from '../ReceiptScreen/utils/utils';
46
+ import {getTextStyle} from '../ReceiptScreen/utils/utils';
47
+ import {getSeparator} from '../ReceiptScreen/utils/utils';
48
+ import SunmiPrepaid from '../../modules/SunmiPrepaid';
49
+
50
+ export function PaymentConfirmation(): JSX.Element {
51
+ const {theme} = useTheme();
52
+ const navigation =
53
+ useNavigation<NativeStackNavigationProp<RootStackParamList>>();
54
+ const scroll = React.useRef<KeyboardAwareScrollView>(null);
55
+ const t = useTranslation();
56
+
57
+ const {service} = useAppSelector((state: RootState) => state.services);
58
+
59
+ const {inquiredBill} = useAppSelector((state: RootState) => state.services);
60
+
61
+ const customProps =
62
+ inquiredBill?.Response?.PresSvcRs?.MsgRqHdr?.CustomProperties
63
+ ?.CustomProperty;
64
+
65
+ const {selectedProvider} = useAppSelector(
66
+ (state: RootState) => state.providers,
67
+ );
68
+ const dispatch = useAppDispatch();
69
+
70
+ const {paymentData} =
71
+ useRoute<RouteProp<RootStackParamList, 'PaymentConfirmation'>>().params;
72
+ const billInfo = inquiredBill?.BillRec?.[0]?.BillInfo;
73
+ let billRec: any = inquiredBill?.BillRec?.[0];
74
+ billRec = omit(billRec, ['BillInfo']);
75
+
76
+ const [isLoading, setIsLoading] = useState(false);
77
+
78
+ const boldTextStyle: TextStyle = {
79
+ ...theme.text.body1,
80
+ fontWeight: 'bold',
81
+ };
82
+
83
+ const isFocused = useIsFocused();
84
+
85
+ const [confirmationData, setConfirmationData] = useState<any[]>([]);
86
+
87
+ useEffect(() => {
88
+ if (!isFocused) {
89
+ return;
90
+ }
91
+ setConfirmationData(
92
+ makePrintData({
93
+ service,
94
+ BillingAcct:
95
+ service?.PmtType === 'POST'
96
+ ? billRec?.BillingAcct
97
+ : paymentData?.fawryInputParameters?.BillingAcct,
98
+ provider: selectedProvider,
99
+ billInfo,
100
+ amuont: paymentData?.amountToBePaid,
101
+ fees: paymentData?.fees,
102
+ ...(paymentData?.quantity && {quantity: paymentData?.quantity}),
103
+ ...(paymentData?.vatValue && {vatValue: paymentData?.vatValue}),
104
+ }),
105
+ );
106
+
107
+ return () => {
108
+ setConfirmationData([]);
109
+ };
110
+ }, [isFocused]);
111
+
112
+ const handleReverse = async (response: any) => {
113
+ try {
114
+ const result = await dispatch(
115
+ reverseService({
116
+ data: {
117
+ id: response?.payload?.data?.results?.find(
118
+ (k: any) => k.label === 'رقم العملية',
119
+ )?.value,
120
+ },
121
+ }),
122
+ );
123
+ if (result.type.includes('fulfilled')) {
124
+ return Alert.alert('تم إعادة الرصيد', 'تم إعادة الرصيد بنجاح', [
125
+ {
126
+ text: 'تم',
127
+ onPress: () => {
128
+ navigation.goBack();
129
+ setTimeout(() => {
130
+ navigation.goBack();
131
+ }, 500);
132
+ },
133
+ },
134
+ ]);
135
+ }
136
+ } catch (error) {
137
+ handleReverse(response);
138
+ }
139
+ };
140
+
141
+ const handleChargeCard = async (response: any) => {
142
+ try {
143
+ if (response?.payload?.data?.chargeValue) {
144
+ const writeRes = await SunmiPrepaid.writeCardCharge(
145
+ response?.payload?.data?.chargeValue,
146
+ response?.payload?.data?.cardMetadata || null,
147
+ );
148
+ if (writeRes) {
149
+ if (response.type.includes('fulfilled')) {
150
+ navigation.navigate('ReceiptScreen', {
151
+ type: 'print',
152
+ });
153
+ }
154
+ }
155
+ } else {
156
+ handleReverse(response);
157
+ }
158
+ } catch (error) {
159
+ handleReverse(response);
160
+ }
161
+ };
162
+
163
+ const handleSubmit = async () => {
164
+ try {
165
+ setIsLoading(true);
166
+ let data = {};
167
+ if (service?.PmtType === 'PREP' || service?.PmtType === 'VOCH') {
168
+ data = {
169
+ ...(service?.PmtType === 'VOCH' && {quantity: paymentData?.quantity}),
170
+ BillTypeCode: service?.BillTypeCode as number,
171
+ PmtType: service?.PmtType as string,
172
+ BillingAcct:
173
+ (paymentData?.fawryInputParameters?.BillingAcct as string) ??
174
+ undefined,
175
+ CurAmt: paymentData?.amountToBePaid,
176
+ ExtraBillingAcctKeys:
177
+ paymentData?.fawryInputParameters?.ExtraBillingAcctKey.filter(
178
+ k => !!k.Value || k.EnumValues,
179
+ ).length > 0
180
+ ? {
181
+ ExtraBillingAcctKey:
182
+ paymentData?.fawryInputParameters?.ExtraBillingAcctKey?.filter(
183
+ k => !!k.Value || k.EnumValues,
184
+ ).map(item => ({
185
+ ...(item.Value && {Key: item.Key}),
186
+ ...(item.Value && {Value: item.Value}),
187
+ ...(item.EnumValues && {
188
+ EnumValues: item.EnumValues,
189
+ }),
190
+ })),
191
+ }
192
+ : undefined,
193
+ };
194
+ } else {
195
+ data = {
196
+ BillTypeCode: billRec?.BillTypeCode as number,
197
+ PmtType: service?.PmtType as string,
198
+ BillingAcct: billRec?.BillingAcct as string,
199
+ BillRefNumber: billRec?.BillRefNumber as string,
200
+ CurAmt: paymentData?.amountToBePaid.toString(),
201
+ ExtraBillingAcctKeys: billRec?.ExtraBillingAcctKeys as string,
202
+ billInfo: billInfo,
203
+ };
204
+ }
205
+
206
+ const response = await dispatch(payService({data}));
207
+
208
+ if (
209
+ service?.AcctInputMethod === 'GASSC' ||
210
+ service?.AcctInputMethod === 'SC' ||
211
+ service?.AcctInputMethod === 'WSC'
212
+ ) {
213
+ handleChargeCard(response);
214
+ } else {
215
+ if (response.type.includes('fulfilled')) {
216
+ navigation.navigate('ReceiptScreen', {
217
+ type: 'print',
218
+ });
219
+ }
220
+ }
221
+ } catch (error) {
222
+ console.error('error: ', error);
223
+ } finally {
224
+ setIsLoading(false);
225
+ }
226
+ };
227
+
228
+ return (
229
+ <Container
230
+ ref={scroll}
231
+ testID={'ReceiptScreenID'}
232
+ contentContainerStyle={styles.contentContainer}
233
+ style={styles.container}
234
+ backgroundImage={ImageResources.background_2}
235
+ withoutPadding
236
+ extendedBackground
237
+ withoutScroll
238
+ bounces={true}
239
+ backgroundColor={theme.colors.background}>
240
+ {isLoading ? (
241
+ <SkypeIndicator size={80} color={theme.colors.mutedLavender} />
242
+ ) : (
243
+ <>
244
+ <HeaderButton onPress={() => navigation.goBack()} />
245
+ <ScrollView
246
+ style={styles.scrollView}
247
+ contentContainerStyle={[
248
+ styles.scrollViewContent,
249
+ {backgroundColor: theme.colors.surface},
250
+ createThemedStyles(theme).dropShadow,
251
+ ]}>
252
+ {Array.isArray(confirmationData) &&
253
+ confirmationData?.map((h, i) => (
254
+ <RTLAwareView
255
+ key={`${h.label}-${i}`}
256
+ style={styles.receiptItem}>
257
+ {getSeparator(h.type, theme)}
258
+ <RTLAwareView
259
+ style={getTextStyle(h.type, theme)?.container as ViewStyle}>
260
+ <RTLAwareText
261
+ style={getTextStyle(h.type, theme)?.value as TextStyle}>
262
+ {h.label === 'VouchPIN'
263
+ ? decryptTripleDES(
264
+ h.value,
265
+ '8pe/hqinrZQV6pHNkQ0WwbD0ZHkaAbbj',
266
+ )
267
+ : normalizeAndTrimWhitespace(h.value)}
268
+ </RTLAwareText>
269
+ {h.label &&
270
+ h.label !== 'VouchPIN' &&
271
+ getLabel(h.type, h.label, theme)}
272
+ </RTLAwareView>
273
+ </RTLAwareView>
274
+ ))}
275
+ </ScrollView>
276
+ <PrimaryButton
277
+ label={t('confirm', 'common')}
278
+ type={ButtonType.solid}
279
+ onPress={handleSubmit}
280
+ />
281
+ <PrimaryButton
282
+ label={t('back', 'common')}
283
+ onPress={() => {
284
+ navigation.goBack();
285
+ }}
286
+ style={styles.backToHomeButton}
287
+ type={ButtonType.outlineNegative}
288
+ />
289
+ </>
290
+ )}
291
+ </Container>
292
+ );
293
+ }
294
+
295
+ const styles = StyleSheet.create({
296
+ container: {
297
+ flexGrow: 1,
298
+ paddingBottom: scaleHeight(20),
299
+ borderTopRightRadius: CommonSizes.spacing.large,
300
+ borderTopLeftRadius: CommonSizes.spacing.large,
301
+ paddingHorizontal: CommonSizes.spacing.large,
302
+ gap: CommonSizes.spacing.xl,
303
+ justifyContent: 'flex-start',
304
+ },
305
+ contentContainer: {
306
+ flexGrow: 1,
307
+ },
308
+ scrollView: {
309
+ width: '100%',
310
+ borderRadius: CommonSizes.borderRadius.medium,
311
+ flexGrow: 1,
312
+ },
313
+ scrollViewContent: {
314
+ paddingHorizontal: CommonSizes.spacing.huge,
315
+ gap: CommonSizes.spacing.large,
316
+ paddingVertical: CommonSizes.spacing.huge,
317
+ flexGrow: 1,
318
+ },
319
+ receiptItem: {
320
+ width: '100%',
321
+ gap: CommonSizes.spacing.medium,
322
+ },
323
+ backToHomeButton: {
324
+ alignSelf: 'flex-end',
325
+ },
326
+ });
@@ -0,0 +1,166 @@
1
+ import {
2
+ RouteProp,
3
+ useIsFocused,
4
+ useNavigation,
5
+ useRoute,
6
+ } from '@react-navigation/native';
7
+ import {NativeStackNavigationProp} from '@react-navigation/native-stack';
8
+ import React, {useEffect, useRef} from 'react';
9
+ import {StyleSheet, View} from 'react-native';
10
+ import {SkypeIndicator} from 'react-native-indicators';
11
+ import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
12
+ import {LoadState} from '../../../types';
13
+ import {Card} from '../../common/components/Cards';
14
+ import {Container} from '../../common/components/Container';
15
+ import {FlatListWrapper} from '../../common/components/FlatListWrapper';
16
+ import {ImageResources} from '../../common/ImageResources.g';
17
+ import {
18
+ resetProviders,
19
+ setSelectedProvider,
20
+ } from '../../core/store/Providers/providersSlice';
21
+ import {ServiceProvider} from '../../core/store/Providers/providersState';
22
+ import {useAppDispatch} from '../../core/store/reduxHelpers';
23
+ import {CommonSizes} from '../../core/theme/commonSizes';
24
+ import {scaleHeight, scaleWidth} from '../../core/theme/scaling';
25
+ import {useTheme} from '../../core/theme/ThemeProvider';
26
+ import {HeaderBack} from '../../navigation/HeaderComponents';
27
+ import {RootStackParamList} from '../../navigation/types';
28
+ import {useProvidersData} from './hooks/useProvidersData';
29
+
30
+ export function Providers(): JSX.Element {
31
+ const dispatch = useAppDispatch();
32
+ const {categoryID} =
33
+ useRoute<RouteProp<RootStackParamList, 'Providers'>>().params;
34
+ const navigation =
35
+ useNavigation<NativeStackNavigationProp<RootStackParamList>>();
36
+ const {fetchData, providers, isLoading} = useProvidersData(categoryID);
37
+ const {theme} = useTheme();
38
+ const scroll = useRef<KeyboardAwareScrollView>(null);
39
+
40
+ function navigateToServices(provider: ServiceProvider) {
41
+ dispatch(setSelectedProvider(provider));
42
+ navigation.navigate('Services', {
43
+ providerID:
44
+ provider?.provider === 'Fawry'
45
+ ? (provider?.BillerId?.toString() as string)
46
+ : (provider?.id?.toString() as string),
47
+ });
48
+ }
49
+ const isFocused = useIsFocused();
50
+
51
+ useEffect(() => {
52
+ if (isFocused) {
53
+ fetchData();
54
+ }
55
+ }, [isFocused]);
56
+
57
+ return (
58
+ <Container
59
+ ref={scroll}
60
+ testID={'ProvidersScreenID'}
61
+ contentContainerStyle={styles.contentContainer}
62
+ style={styles.container}
63
+ backgroundImage={ImageResources[`${theme.mode}_background_1`]}
64
+ withoutPadding
65
+ withoutScroll
66
+ backgroundColor={theme.colors.background}>
67
+ {isLoading ? (
68
+ <SkypeIndicator size={80} color={theme.colors.mutedLavender} />
69
+ ) : (
70
+ <>
71
+ <HeaderBack
72
+ onPress={() => {
73
+ dispatch(resetProviders());
74
+ navigation.goBack();
75
+ }}
76
+ />
77
+
78
+ <FlatListWrapper
79
+ contentContainerStyle={{
80
+ alignItems: 'flex-start',
81
+ paddingBottom: scaleHeight(50),
82
+ paddingLeft: CommonSizes.spacing.medium,
83
+ }}
84
+ style={{
85
+ flex: 1,
86
+ alignSelf: 'flex-start',
87
+ }}
88
+ ItemSeparatorComponent={() => (
89
+ <View style={{height: CommonSizes.spacing.large}} />
90
+ )}
91
+ keyExtractor={(item, index) => `${item.id}-${index}`}
92
+ loadState={LoadState.needLoad}
93
+ data={providers}
94
+ numColumns={3}
95
+ renderItem={({item, index}) => {
96
+ return (
97
+ <Card
98
+ cardStyle={{
99
+ width: scaleWidth(187),
100
+ height: scaleHeight(260),
101
+ }}
102
+ key={item.id}
103
+ icon={{uri: item.img_url}}
104
+ title={item.name || item?.BillerName}
105
+ onPress={() => {
106
+ navigateToServices(item);
107
+ }}
108
+ marginRight={
109
+ (index % 3) + 1 !== 3
110
+ ? CommonSizes.spacing.medium
111
+ : undefined
112
+ }
113
+ />
114
+ );
115
+ }}
116
+ />
117
+ </>
118
+ )}
119
+ </Container>
120
+ );
121
+ }
122
+
123
+ const styles = StyleSheet.create({
124
+ container: {
125
+ flexGrow: 1,
126
+ borderTopRightRadius: CommonSizes.spacing.large,
127
+ borderTopLeftRadius: CommonSizes.spacing.large,
128
+ gap: CommonSizes.spacing.large,
129
+ justifyContent: 'flex-start',
130
+ alignItems: 'center',
131
+ },
132
+ contentContainer: {
133
+ flexGrow: 1,
134
+ },
135
+ searchBar: {
136
+ width: '90%',
137
+ alignSelf: 'center',
138
+ marginTop: CommonSizes.spacing.medium,
139
+ },
140
+ formContainer: {
141
+ alignItems: 'center',
142
+ paddingHorizontal: CommonSizes.spacing.large,
143
+ gap: CommonSizes.spacing.large,
144
+ },
145
+ balanceSection: {
146
+ alignItems: 'center',
147
+ justifyContent: 'space-evenly',
148
+ gap: CommonSizes.spacing.large,
149
+ },
150
+ seeMoreSection: {
151
+ alignItems: 'center',
152
+ gap: CommonSizes.spacing.large,
153
+ alignSelf: 'center',
154
+ },
155
+ sectionImage: {
156
+ width: scaleWidth(120),
157
+ height: scaleHeight(70),
158
+ },
159
+ amountText: {
160
+ textAlign: 'left',
161
+ },
162
+ balanceCard: {
163
+ width: '100%',
164
+ borderRadius: CommonSizes.spacing.huge,
165
+ },
166
+ });
@@ -0,0 +1,33 @@
1
+ import {useState} from 'react';
2
+ import {getProviders} from '../../../core/store/Providers/providersActions';
3
+ import {useAppDispatch, useAppSelector} from '../../../core/store/reduxHelpers';
4
+ import {RootState} from '../../../core/store/rootReducer';
5
+ export function useProvidersData(categoryID: string) {
6
+ const [isLoading, setIsLoading] = useState(false);
7
+ const dispatch = useAppDispatch();
8
+ const {providers} = useAppSelector((state: RootState) => state.providers);
9
+
10
+ const fetchData = async () => {
11
+ setIsLoading(true);
12
+ try {
13
+ await dispatch(
14
+ getProviders({data: {limit: 5000, category_id: Number(categoryID)}}),
15
+ );
16
+ } catch (error) {
17
+ console.error('Error fetching home data:', error);
18
+ } finally {
19
+ setIsLoading(false);
20
+ }
21
+ };
22
+
23
+ const refreshData = () => {
24
+ fetchData();
25
+ };
26
+
27
+ return {
28
+ isLoading,
29
+ refreshData,
30
+ fetchData,
31
+ providers,
32
+ };
33
+ }
@@ -0,0 +1,7 @@
1
+ export interface CarouselItem {
2
+ id: string;
3
+ title: string;
4
+ subtitle?: string;
5
+ imageUrl: string;
6
+ onPress?: (item: CarouselItem) => void;
7
+ }