@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,164 @@
1
+ import {useState} from 'react';
2
+ import {useAppDispatch, useAppSelector} from '../../../core/store/reduxHelpers';
3
+ import {RootState} from '../../../core/store/rootReducer';
4
+ import {
5
+ enquireService,
6
+ getService,
7
+ payService,
8
+ } from '../../../core/store/Services/servicesActions';
9
+ import {BillTypeRefKeyEntity} from '../../../core/store/Services/servicesState';
10
+ import {useNavigation} from '@react-navigation/native';
11
+ import {NativeStackNavigationProp} from '@react-navigation/native-stack';
12
+ import {RootStackParamList} from '../../../navigation/types';
13
+ import {
14
+ clearInquiry,
15
+ clearPayment,
16
+ } from '../../../core/store/Services/servicesSlice';
17
+ import {initFees} from '../../../common/utils';
18
+ interface InputParameter {
19
+ BillingAcct: string;
20
+ ExtraBillingAcctKey: BillTypeRefKeyEntity[];
21
+ }
22
+
23
+ export function useServiceData(serviceID?: string) {
24
+ const [isLoading, setIsLoading] = useState(false);
25
+ const dispatch = useAppDispatch();
26
+ const {service} = useAppSelector((state: RootState) => state.services);
27
+
28
+ const [cardRead, setCardRead] = useState<any>(null);
29
+ const {selectedProvider} = useAppSelector(
30
+ (state: RootState) => state.providers,
31
+ );
32
+ const navigation =
33
+ useNavigation<NativeStackNavigationProp<RootStackParamList>>();
34
+ const [selectedPaymentRange, setSelectedPaymentRange] = useState<any>(null);
35
+ const [quantity, setQuantity] = useState<string>('1');
36
+ const [vatValue, setVatValue] = useState<string>('');
37
+ const [customProperties, setCustomProperties] = useState<any>(null);
38
+ const [beeInputParameters, setBeeInputParameters] = useState<any>([]);
39
+ const [fawryInputParameters, setFawryInputParameters] =
40
+ useState<InputParameter>({
41
+ BillingAcct: '',
42
+ ExtraBillingAcctKey:
43
+ service?.BillTypeExtraRefKeys?.BillTypeRefKey?.map(i => {
44
+ return {...i, Value: ''};
45
+ }) || [],
46
+ });
47
+ const fees = initFees(service, selectedPaymentRange);
48
+
49
+ const handlePayment = async () => {
50
+ setIsLoading(false);
51
+ navigation.navigate('PaymentConfirmation', {
52
+ paymentData: {
53
+ amountToBePaid: selectedPaymentRange,
54
+ ...(service?.PmtType === 'VOCH' && {quantity}),
55
+ fawryInputParameters,
56
+ fees,
57
+ ...(vatValue && {vatValue}),
58
+ },
59
+ });
60
+ };
61
+
62
+ const handleEnquireService = async () => {
63
+ setIsLoading(true);
64
+ dispatch(clearInquiry());
65
+ dispatch(clearPayment());
66
+ try {
67
+ const data = {
68
+ BillTypeCode: service.BillTypeCode,
69
+ PmtType: service?.PmtType,
70
+ BillingAcct: fawryInputParameters?.BillingAcct,
71
+ ExtraBillingAcctKeys:
72
+ fawryInputParameters?.ExtraBillingAcctKey.filter(
73
+ k => !!k.Value || k.EnumValues,
74
+ ).length > 0
75
+ ? {
76
+ ExtraBillingAcctKey:
77
+ fawryInputParameters?.ExtraBillingAcctKey?.filter(
78
+ k => !!k.Value || k.EnumValues,
79
+ ).map(item => ({
80
+ ...(item.Value && {Key: item.Key}),
81
+ ...(item.Value && {Value: item.Value}),
82
+ ...(item.EnumValues && {
83
+ EnumValues: item.EnumValues,
84
+ }),
85
+ })),
86
+ }
87
+ : undefined,
88
+ ...(service?.ServiceType === 'UTL' &&
89
+ customProperties && {
90
+ CustomProperties: {CustomProperty: customProperties},
91
+ }),
92
+ };
93
+
94
+ if (service?.PmtType === 'PREP' || service?.PmtType === 'VOCH') {
95
+ handlePayment();
96
+ } else {
97
+ const response = await dispatch(enquireService({data}));
98
+ if (response.type.includes('fulfilled')) {
99
+ navigation.navigate('InquiredBill');
100
+ }
101
+ }
102
+ } catch (error) {
103
+ console.log('error: ', error);
104
+ } finally {
105
+ if (service?.PmtType === 'POST') {
106
+ setIsLoading(false);
107
+ }
108
+ }
109
+ };
110
+
111
+ const fetchData = async () => {
112
+ if (!serviceID) {
113
+ return;
114
+ }
115
+ try {
116
+ setIsLoading(true);
117
+ const data =
118
+ selectedProvider?.provider === 'Fawry'
119
+ ? {fawry_service_id: serviceID}
120
+ : {bee_service_id: serviceID};
121
+ const res = await dispatch(getService({data}));
122
+
123
+ setFawryInputParameters({
124
+ ...fawryInputParameters,
125
+ ExtraBillingAcctKey:
126
+ res.payload.service?.BillTypeExtraRefKeys?.BillTypeRefKey?.map(
127
+ (i: BillTypeRefKeyEntity) => {
128
+ return {...i, Value: ''};
129
+ },
130
+ ) || [],
131
+ });
132
+ } catch (error) {
133
+ console.error('Error fetching service data:', error);
134
+ } finally {
135
+ setIsLoading(false);
136
+ }
137
+ };
138
+
139
+ const refreshData = () => {
140
+ fetchData();
141
+ };
142
+
143
+ return {
144
+ beeInputParameters,
145
+ setBeeInputParameters,
146
+ fawryInputParameters,
147
+ setFawryInputParameters,
148
+ isLoading,
149
+ refreshData,
150
+ fetchData,
151
+ selectedPaymentRange,
152
+ setSelectedPaymentRange,
153
+ quantity,
154
+ setQuantity,
155
+ vatValue,
156
+ setVatValue,
157
+ selectedProvider,
158
+ handleEnquireService,
159
+ handlePayment,
160
+ fees,
161
+ customProperties,
162
+ setCustomProperties,
163
+ };
164
+ }
@@ -0,0 +1,129 @@
1
+ import React, {useState} from 'react';
2
+ import {Modal, StyleSheet, View} from 'react-native';
3
+ import {RTLAwareView} from '../../../common/components/RTLAwareView';
4
+ import {CommonSizes} from '../../../core/theme/commonSizes';
5
+ import {PrimaryTextInput} from '../../../common/components/PrimaryTextInput';
6
+ import {useTheme} from '../../../core/theme/ThemeProvider';
7
+ import {PrimaryButton} from '../../../common/components/PrimaryButton';
8
+ import {ButtonType} from '../../../../types';
9
+ import {useAppDispatch} from '../../../core/store/reduxHelpers';
10
+ import {getServiceById} from '../../../core/store/Services/servicesActions';
11
+ import {getProviderById} from '../../../core/store/Providers/providersActions';
12
+ import {useNavigation} from '@react-navigation/native';
13
+ import {NativeStackNavigationProp} from '@react-navigation/native-stack';
14
+ import {RootStackParamList} from '../../../navigation/types';
15
+ import {useTranslation} from '../../../common/localization/LocalizationProvider';
16
+
17
+ export function PayByCode({
18
+ isVisible,
19
+ onClose,
20
+ }: {
21
+ isVisible: boolean;
22
+ onClose: () => void;
23
+ }): JSX.Element {
24
+ const {theme} = useTheme();
25
+ const t = useTranslation();
26
+ const [code, setCode] = useState('');
27
+ const [isLoading, setIsLoading] = useState(false);
28
+ const dispatch = useAppDispatch();
29
+ const navigation =
30
+ useNavigation<NativeStackNavigationProp<RootStackParamList>>();
31
+
32
+ const getService = async () => {
33
+ if (!code) {
34
+ return;
35
+ }
36
+ try {
37
+ setIsLoading(true);
38
+ const response = await dispatch(
39
+ getServiceById({data: {BillTypeCode: code}}),
40
+ );
41
+ if (response.type.includes('fulfilled')) {
42
+ const providerResponse = await dispatch(
43
+ getProviderById({
44
+ data: {BillerId: response.payload.service.BillerId},
45
+ }),
46
+ );
47
+ if (providerResponse.type.includes('fulfilled')) {
48
+ setCode('');
49
+ onClose();
50
+ setTimeout(() => {
51
+ navigation.navigate('SingleService', {
52
+ serviceID: undefined,
53
+ });
54
+ }, 200);
55
+ }
56
+ }
57
+ } catch (error) {
58
+ console.error(error);
59
+ } finally {
60
+ setIsLoading(false);
61
+ }
62
+ };
63
+
64
+ return (
65
+ <Modal
66
+ onRequestClose={onClose}
67
+ visible={isVisible}
68
+ transparent
69
+ style={styles.modal}>
70
+ <RTLAwareView
71
+ style={{
72
+ ...styles.container,
73
+ backgroundColor: theme.colors.surface,
74
+ borderWidth: 1,
75
+ borderColor: theme.colors.indigoBlue,
76
+ }}>
77
+ <PrimaryTextInput
78
+ value={code}
79
+ onChangeText={setCode}
80
+ placeholder={t('enterCode', 'home')}
81
+ />
82
+ <RTLAwareView
83
+ style={{
84
+ flexDirection: 'row',
85
+ alignItems: 'center',
86
+ justifyContent: 'space-between',
87
+ }}>
88
+ <PrimaryButton
89
+ disabled={isLoading}
90
+ isLoading={isLoading}
91
+ onPress={() => {
92
+ onClose();
93
+ setCode('');
94
+ }}
95
+ style={{width: '48%'}}
96
+ label={t('cancel', 'home')}
97
+ type={ButtonType.solid}
98
+ />
99
+ <PrimaryButton
100
+ disabled={isLoading}
101
+ isLoading={isLoading}
102
+ onPress={getService}
103
+ style={{width: '48%'}}
104
+ label={t('search', 'home')}
105
+ type={ButtonType.solid}
106
+ />
107
+ </RTLAwareView>
108
+ </RTLAwareView>
109
+ </Modal>
110
+ );
111
+ }
112
+
113
+ const styles = StyleSheet.create({
114
+ modal: {
115
+ flex: 1,
116
+ backgroundColor: 'red',
117
+ alignItems: 'center',
118
+ justifyContent: 'center',
119
+ },
120
+ container: {
121
+ width: '95%',
122
+ // minHeight: '40%',
123
+ alignSelf: 'center',
124
+ borderRadius: CommonSizes.borderRadius.large,
125
+ padding: CommonSizes.spacing.large,
126
+ gap: CommonSizes.spacing.large,
127
+ marginTop: '45%',
128
+ },
129
+ });
@@ -1,107 +1,298 @@
1
- import React from 'react';
1
+ import {useIsFocused, useNavigation} from '@react-navigation/native';
2
+ import {NativeStackNavigationProp} from '@react-navigation/native-stack';
3
+ import React, {useEffect, useRef} from 'react';
4
+ import {Image, ImageURISource, StyleSheet, View, ViewStyle} from 'react-native';
5
+ import {SkypeIndicator} from 'react-native-indicators';
6
+ import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
7
+ import {ButtonType} from '../../../types';
8
+ import {Card} from '../../common/components/Cards';
9
+ import {Container} from '../../common/components/Container';
10
+ import {FlatListWrapper} from '../../common/components/FlatListWrapper';
11
+ import {PrimaryButton} from '../../common/components/PrimaryButton';
12
+ import {RTLAwareText} from '../../common/components/RTLAwareText';
13
+ import {RTLAwareView} from '../../common/components/RTLAwareView';
14
+ import {ImageResources} from '../../common/ImageResources.g';
2
15
  import {
3
- Dimensions,
4
- RefreshControl,
5
- ScrollView,
6
- StyleSheet,
7
- Text,
8
- View,
9
- } from 'react-native';
10
- import {NaturalColors} from '../../core/theme/colors';
16
+ useRTL,
17
+ useTranslation,
18
+ } from '../../common/localization/LocalizationProvider';
19
+ import {
20
+ clearSelectedCategory,
21
+ setSelectedCategory,
22
+ } from '../../core/store/Categories/categorySlice';
23
+ import {Category} from '../../core/store/Categories/categoryState';
24
+ import {setSelectedProvider} from '../../core/store/Providers/providersSlice';
25
+ import {ServiceProvider} from '../../core/store/Providers/providersState';
26
+ import {useAppDispatch, useAppSelector} from '../../core/store/reduxHelpers';
27
+ import {RootState} from '../../core/store/rootReducer';
28
+ import {UserStatus} from '../../core/store/user/userState';
11
29
  import {CommonSizes} from '../../core/theme/commonSizes';
12
- import {CommonStyles} from '../../core/theme/commonStyles';
13
- import {CarouselSection} from './components/CarouselSection';
14
- import {FeaturedCarousel} from './components/FeaturedCarousel';
30
+ import {scaleHeight, scaleWidth} from '../../core/theme/scaling';
31
+ import {useTheme} from '../../core/theme/ThemeProvider';
32
+ import {HomeHeader} from '../../navigation/HeaderComponents';
33
+ import {RootStackParamList} from '../../navigation/types';
15
34
  import {useHomeData} from './hooks/useHomeData';
35
+ import {PayByCode} from './Components/PayByCode';
36
+
37
+ // Props for balance section component
38
+ interface BalanceSectionProps {
39
+ title: string;
40
+ image: ImageURISource;
41
+ amount?: string;
42
+ style?: ViewStyle;
43
+ }
44
+
45
+ // Balance section component
46
+ function BalanceSections({
47
+ title,
48
+ image,
49
+ amount,
50
+ style,
51
+ }: BalanceSectionProps): JSX.Element {
52
+ const {theme} = useTheme();
53
+ const t = useTranslation();
54
+
55
+ return (
56
+ <View style={[styles.balanceSection, style]}>
57
+ <Image
58
+ style={{...styles.sectionImage, tintColor: theme.colors.tintColor}}
59
+ source={image}
60
+ resizeMode="contain"
61
+ />
62
+ <RTLAwareText style={[theme.text.balanceAmount, styles.amountText]}>
63
+ <RTLAwareText style={theme.text.balanceLabel}>
64
+ {t('currency') + '\n'}
65
+ </RTLAwareText>
66
+ {amount}
67
+ </RTLAwareText>
68
+ <RTLAwareText style={theme.text.balanceTitle}>{title}</RTLAwareText>
69
+ </View>
70
+ );
71
+ }
16
72
 
17
- const {width} = Dimensions.get('window');
73
+ // Props for see more section component
74
+ interface SeeMoreSectionProps {
75
+ title: string;
76
+ image: ImageURISource;
77
+ style?: ViewStyle;
78
+ }
79
+
80
+ // See more section component
81
+ function SeeMoreSection({
82
+ title,
83
+ image,
84
+ style,
85
+ }: SeeMoreSectionProps): JSX.Element {
86
+ const {theme} = useTheme();
87
+ return (
88
+ <View style={[styles.seeMoreSection, style]}>
89
+ <RTLAwareText style={theme.text.balanceTitle}>{title}</RTLAwareText>
90
+ <Image
91
+ style={{...styles.sectionImage, tintColor: theme.colors.tintColor}}
92
+ source={image}
93
+ resizeMode="contain"
94
+ />
95
+ </View>
96
+ );
97
+ }
98
+
99
+ // Balance card component
100
+ function BalanceCard(): JSX.Element {
101
+ const {theme} = useTheme();
102
+ const t = useTranslation();
103
+ const isRTL = useRTL();
104
+ const {current_balance, daily_commission} = useAppSelector(
105
+ (state: RootState) => state.user,
106
+ );
107
+
108
+ return (
109
+ <RTLAwareView
110
+ style={[
111
+ styles.balanceCard,
112
+ {backgroundColor: theme.colors.balanceBackground},
113
+ ]}>
114
+ <RTLAwareView
115
+ style={{
116
+ width: '100%',
117
+ flexDirection: 'row',
118
+ justifyContent: 'space-evenly',
119
+ paddingVertical: CommonSizes.spacing.large,
120
+ }}>
121
+ <BalanceSections
122
+ title={t('currentBalance', 'home')}
123
+ image={ImageResources.balance}
124
+ amount={`${current_balance?.toFixed(2) ?? 0}`}
125
+ />
126
+ <BalanceSections
127
+ title={t('dailyCommission', 'home')}
128
+ image={ImageResources.commission}
129
+ amount={`${daily_commission ?? 0}`}
130
+ />
131
+ </RTLAwareView>
132
+ </RTLAwareView>
133
+ );
134
+ }
18
135
 
19
136
  export function HomeScreen(): JSX.Element {
20
137
  const {
21
- featuredItems,
22
- trendingItems,
23
- newItems,
24
- recommendedItems,
25
138
  isLoading,
26
139
  refreshData,
140
+ fetchData,
141
+ user,
142
+ categories,
143
+ loadState,
144
+ homeProviders,
145
+ isPayByCodeModalVisible,
146
+ setIsPayByCodeModalVisible,
27
147
  } = useHomeData();
148
+ const dispatch = useAppDispatch();
149
+
150
+ const t = useTranslation();
151
+
152
+ const navigation =
153
+ useNavigation<NativeStackNavigationProp<RootStackParamList>>();
154
+
155
+ const {theme} = useTheme();
156
+ const scroll = useRef<KeyboardAwareScrollView>(null);
157
+ const isFocused = useIsFocused();
158
+
159
+ useEffect(() => {
160
+ if (user.status === UserStatus.REGISTERED) {
161
+ navigation.navigate('ForceChangePassword');
162
+ }
163
+ }, [user.status]);
164
+
165
+ useEffect(() => {
166
+ if (categories.length === 0) {
167
+ fetchData();
168
+ }
169
+ }, [isFocused]);
170
+
171
+ function navigateToServices(provider: ServiceProvider) {
172
+ dispatch(clearSelectedCategory());
173
+ setTimeout(() => {
174
+ dispatch(setSelectedProvider(provider));
175
+ navigation.navigate('Services', {
176
+ providerID:
177
+ provider?.provider === 'Fawry'
178
+ ? provider?.BillerId?.toString()
179
+ : (provider?.id?.toString() as string),
180
+ });
181
+ }, 200);
182
+ }
183
+
184
+ function navigateToProviders(category: Category) {
185
+ dispatch(setSelectedCategory(category));
186
+ navigation.navigate('Providers', {
187
+ categoryID: category.id?.toString(),
188
+ });
189
+ }
28
190
 
29
191
  return (
30
- <ScrollView
192
+ <Container
193
+ ref={scroll}
194
+ testID={'HomeScreenID'}
195
+ contentContainerStyle={styles.contentContainer}
31
196
  style={styles.container}
32
- refreshControl={
33
- <RefreshControl refreshing={isLoading} onRefresh={refreshData} />
34
- }>
35
- <View style={styles.content}>
36
- {/* Featured Section */}
37
- <View style={styles.featuredSection}>
38
- <Text style={styles.sectionTitle}>Featured</Text>
39
- <FeaturedCarousel items={featuredItems} />
40
- </View>
41
-
42
- {/* Trending Section */}
43
- <View style={styles.carouselSection}>
44
- <Text style={styles.sectionTitle}>Trending Now</Text>
45
- <CarouselSection
46
- items={trendingItems}
47
- imageStyle={styles.trendingImage}
197
+ backgroundImage={ImageResources[`${theme.mode}_background_1`]}
198
+ withoutPadding
199
+ backgroundColor={theme.colors.background}>
200
+ {isLoading ? (
201
+ <SkypeIndicator size={80} color={theme.colors.mutedLavender} />
202
+ ) : (
203
+ <>
204
+ <HomeHeader onPress={refreshData} />
205
+ <PrimaryButton
206
+ label={t('payByCode', 'home')}
207
+ type={ButtonType.solid}
208
+ onPress={() => setIsPayByCodeModalVisible(!isPayByCodeModalVisible)}
209
+ />
210
+ <BalanceCard />
211
+ <PrimaryButton
212
+ onPressIn={async () => {
213
+ navigation.navigate('Categories');
214
+ }}
215
+ label={t('allServices', 'common')}
216
+ type={ButtonType.solid}
48
217
  />
49
- </View>
50
-
51
- {/* New Arrivals Section */}
52
- <View style={styles.carouselSection}>
53
- <Text style={styles.sectionTitle}>New Arrivals</Text>
54
- <CarouselSection
55
- items={newItems}
56
- imageStyle={styles.newArrivalsImage}
218
+ <FlatListWrapper
219
+ keyExtractor={(item, index) => `${item.id}-${index}`}
220
+ loadState={loadState}
221
+ data={categories?.slice(1, 6)}
222
+ horizontal
223
+ renderItem={({item}) => (
224
+ <Card
225
+ key={item.id}
226
+ icon={{uri: item.img_url}}
227
+ title={item.name}
228
+ onPress={() => {
229
+ navigateToProviders(item);
230
+ }}
231
+ marginRight={CommonSizes.spacing.extraLarge}
232
+ />
233
+ )}
57
234
  />
58
- </View>
59
-
60
- {/* Recommended Section */}
61
- <View style={styles.carouselSection}>
62
- <Text style={styles.sectionTitle}>Recommended for You</Text>
63
- <CarouselSection
64
- items={recommendedItems}
65
- imageStyle={styles.recommendedImage}
235
+ <FlatListWrapper
236
+ keyExtractor={(item, index) => `${item.id}-${index}`}
237
+ loadState={loadState}
238
+ data={homeProviders?.slice(0, 5)}
239
+ horizontal
240
+ renderItem={({item}) => (
241
+ <Card
242
+ key={item.id}
243
+ icon={{uri: item.img_url}}
244
+ title={item.name || item.BillerName}
245
+ onPress={() => navigateToServices(item)}
246
+ marginRight={CommonSizes.spacing.extraLarge}
247
+ />
248
+ )}
66
249
  />
67
- </View>
68
- </View>
69
- </ScrollView>
250
+ </>
251
+ )}
252
+ <PayByCode
253
+ isVisible={isPayByCodeModalVisible}
254
+ onClose={() => setIsPayByCodeModalVisible(false)}
255
+ />
256
+ </Container>
70
257
  );
71
258
  }
72
259
 
73
260
  const styles = StyleSheet.create({
74
261
  container: {
75
- flex: 1,
76
- backgroundColor: NaturalColors.grayScale_0,
262
+ paddingBottom: scaleHeight(130),
263
+ borderTopRightRadius: CommonSizes.spacing.large,
264
+ borderTopLeftRadius: CommonSizes.spacing.large,
265
+ paddingHorizontal: CommonSizes.spacing.large,
266
+ gap: CommonSizes.spacing.large,
267
+ justifyContent: 'flex-start',
77
268
  },
78
- content: {
79
- paddingVertical: CommonSizes.spacing.medium,
269
+ contentContainer: {
270
+ flexGrow: 1,
80
271
  },
81
- featuredSection: {
82
- marginBottom: CommonSizes.spacing.large,
272
+ formContainer: {
273
+ alignItems: 'center',
274
+ paddingHorizontal: CommonSizes.spacing.large,
275
+ gap: CommonSizes.spacing.large,
83
276
  },
84
- carouselSection: {
85
- marginBottom: CommonSizes.spacing.large,
277
+ balanceSection: {
278
+ alignItems: 'center',
279
+ justifyContent: 'space-evenly',
280
+ gap: CommonSizes.spacing.large,
86
281
  },
87
- sectionTitle: {
88
- ...CommonStyles.h2_semiBold,
89
- marginHorizontal: CommonSizes.spacing.large,
90
- marginBottom: CommonSizes.spacing.medium,
282
+ seeMoreSection: {
283
+ alignItems: 'center',
284
+ gap: CommonSizes.spacing.large,
285
+ alignSelf: 'center',
91
286
  },
92
- trendingImage: {
93
- width: width * 0.7,
94
- height: 200,
95
- borderRadius: CommonSizes.borderRadius.medium,
287
+ sectionImage: {
288
+ width: scaleWidth(120),
289
+ height: scaleHeight(70),
96
290
  },
97
- newArrivalsImage: {
98
- width: width * 0.5,
99
- height: 180,
100
- borderRadius: CommonSizes.borderRadius.medium,
291
+ amountText: {
292
+ textAlign: 'left',
101
293
  },
102
- recommendedImage: {
103
- width: width * 0.6,
104
- height: 160,
105
- borderRadius: CommonSizes.borderRadius.medium,
294
+ balanceCard: {
295
+ width: '100%',
296
+ borderRadius: CommonSizes.spacing.huge,
106
297
  },
107
298
  });