@fadyshawky/react-native-magic 2.0.3 → 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,33 @@
1
+ import {useEffect, useState} from 'react';
2
+ import {getCategories} from '../../../core/store/Categories/categoryActions';
3
+ import {getProviders} from '../../../core/store/Providers/providersActions';
4
+ import {useAppDispatch, useAppSelector} from '../../../core/store/reduxHelpers';
5
+ import {RootState} from '../../../core/store/rootReducer';
6
+ export function useCategoriesData() {
7
+ const [isLoading, setIsLoading] = useState(false);
8
+
9
+ const dispatch = useAppDispatch();
10
+ const {categories} = useAppSelector((state: RootState) => state.categories);
11
+
12
+ const fetchData = async () => {
13
+ setIsLoading(true);
14
+ try {
15
+ const categories = await dispatch(getCategories({data: {limit: 30}}));
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
+ categories,
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
+ }
@@ -0,0 +1,130 @@
1
+ import {useNavigation} from '@react-navigation/native';
2
+ import {NativeStackNavigationProp} from '@react-navigation/native-stack';
3
+ import React, {useCallback, useRef} from 'react';
4
+ import {StyleSheet} from 'react-native';
5
+ import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
6
+ import {Container} from '../../common/components/Container';
7
+ import {RTLAwareText} from '../../common/components/RTLAwareText';
8
+ import {RTLAwareView} from '../../common/components/RTLAwareView';
9
+ import {ImageResources} from '../../common/ImageResources.g';
10
+ import {
11
+ useRTL,
12
+ useTranslation,
13
+ } from '../../common/localization/LocalizationProvider';
14
+ import {setSelectedProvider} from '../../core/store/Providers/providersSlice';
15
+ import {ServiceProvider} from '../../core/store/Providers/providersState';
16
+ import {useAppDispatch, useAppSelector} from '../../core/store/reduxHelpers';
17
+ import {RootState} from '../../core/store/rootReducer';
18
+ import {CommonSizes} from '../../core/theme/commonSizes';
19
+ import {scaleHeight} from '../../core/theme/scaling';
20
+ import {useTheme} from '../../core/theme/ThemeProvider';
21
+ import {Header} from '../../navigation/HeaderComponents';
22
+ import {RootStackParamList} from '../../navigation/types';
23
+
24
+ export function Favorites(): JSX.Element {
25
+ const dispatch = useAppDispatch();
26
+ const {favoriteProviders = []} = useAppSelector(
27
+ (state: RootState) => state.user,
28
+ );
29
+ const {favoriteCategories = []} = useAppSelector(
30
+ (state: RootState) => state.user,
31
+ );
32
+ const {providers} = useAppSelector((state: RootState) => state.providers);
33
+ const {categories} = useAppSelector((state: RootState) => state.categories);
34
+ const t = useTranslation();
35
+ const isRTL = useRTL();
36
+ const navigation =
37
+ useNavigation<NativeStackNavigationProp<RootStackParamList>>();
38
+ const {theme} = useTheme();
39
+ const scroll = useRef<KeyboardAwareScrollView>(null);
40
+
41
+ const navigateToServices = useCallback(
42
+ (provider: ServiceProvider) => {
43
+ dispatch(setSelectedProvider(provider));
44
+ navigation.navigate('Services', {
45
+ providerID: provider?.id?.toString() as string,
46
+ });
47
+ },
48
+ [dispatch, navigation],
49
+ );
50
+
51
+ return (
52
+ <Container
53
+ ref={scroll}
54
+ testID={'FavoritesScreenID'}
55
+ contentContainerStyle={styles.contentContainer}
56
+ style={styles.container}
57
+ backgroundImage={ImageResources[`${theme.mode}_background_1`]}
58
+ withoutPadding
59
+ backgroundColor={theme.colors.background}>
60
+ <Header />
61
+
62
+ <RTLAwareView style={styles.sectionHeader}>
63
+ <RTLAwareText style={theme.text.header2}>
64
+ {t('favoriteCategories', 'common')}
65
+ </RTLAwareText>
66
+ </RTLAwareView>
67
+ </Container>
68
+ );
69
+ }
70
+
71
+ const styles = StyleSheet.create({
72
+ container: {
73
+ flexGrow: 1,
74
+ paddingBottom: scaleHeight(150),
75
+ borderTopRightRadius: CommonSizes.spacing.large,
76
+ borderTopLeftRadius: CommonSizes.spacing.large,
77
+ gap: CommonSizes.spacing.medium,
78
+ justifyContent: 'flex-start',
79
+ alignItems: 'center',
80
+ },
81
+ contentContainer: {
82
+ flexGrow: 1,
83
+ },
84
+ searchBar: {
85
+ width: '90%',
86
+ alignSelf: 'center',
87
+ marginTop: CommonSizes.spacing.medium,
88
+ },
89
+ sectionHeader: {
90
+ width: '90%',
91
+ marginVertical: CommonSizes.spacing.medium,
92
+ },
93
+ carouselContainer: {
94
+ height: scaleHeight(570),
95
+ width: '100%',
96
+ },
97
+ gridPage: {
98
+ flexDirection: 'row',
99
+ flexWrap: 'wrap',
100
+ justifyContent: 'flex-start',
101
+ alignItems: 'center',
102
+ paddingHorizontal: CommonSizes.spacing.large,
103
+ overflow: 'hidden',
104
+ },
105
+ paginationContainer: {
106
+ flexDirection: 'row',
107
+ justifyContent: 'center',
108
+ alignItems: 'center',
109
+ marginTop: CommonSizes.spacing.small,
110
+ },
111
+ paginationDot: {
112
+ width: 8,
113
+ height: 8,
114
+ borderRadius: 4,
115
+ backgroundColor: '#cccccc',
116
+ marginHorizontal: 4,
117
+ },
118
+ paginationDotActive: {
119
+ backgroundColor: '#666666',
120
+ width: 10,
121
+ height: 10,
122
+ borderRadius: 5,
123
+ },
124
+ emptyContainer: {
125
+ height: scaleHeight(150),
126
+ width: '100%',
127
+ justifyContent: 'center',
128
+ alignItems: 'center',
129
+ },
130
+ });
@@ -0,0 +1,155 @@
1
+ import {useNavigation} from '@react-navigation/native';
2
+ import type {NativeStackNavigationProp} from '@react-navigation/native-stack';
3
+ import React, {useRef, useState} from 'react';
4
+ import {StyleSheet, Text} from 'react-native';
5
+ import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
6
+ import {ButtonType} from '../../../types';
7
+ import {Container} from '../../common/components/Container';
8
+ import {PrimaryButton} from '../../common/components/PrimaryButton';
9
+ import {PrimaryTextInput} from '../../common/components/PrimaryTextInput';
10
+ import {ImageResources} from '../../common/ImageResources.g';
11
+ import {useInputError} from '../../common/validations/hooks/useInputError';
12
+ import {useAppDispatch} from '../../core/store/reduxHelpers';
13
+ import {CommonSizes} from '../../core/theme/commonSizes';
14
+ import {useTheme} from '../../core/theme/ThemeProvider';
15
+ import {Header} from '../../navigation/HeaderComponents';
16
+ import type {RootStackParamList} from '../../navigation/types';
17
+ import {resetPassword} from '../../core/store/user/userActions';
18
+ import {
19
+ useTranslation,
20
+ useRTL,
21
+ } from '../../common/localization/LocalizationProvider';
22
+ import {RTLAwareText} from '../../common/components/RTLAwareText';
23
+ import {RTLAwareView} from '../../common/components/RTLAwareView';
24
+
25
+ export function ForceChangePasswordScreen(): JSX.Element {
26
+ const dispatch = useAppDispatch();
27
+ const [currentPassword, setCurrentPassword] = useState('');
28
+ const [newPassword, setNewPassword] = useState('');
29
+ const [confirmPassword, setConfirmPassword] = useState('');
30
+ const [loading, setLoading] = useState(false);
31
+ const navigation =
32
+ useNavigation<NativeStackNavigationProp<RootStackParamList>>();
33
+ const scroll = useRef<KeyboardAwareScrollView>(null);
34
+ const {theme} = useTheme();
35
+ const t = useTranslation();
36
+ const isRTL = useRTL();
37
+
38
+ const {error: currentPasswordError, recheckValue: recheckCurrentPassword} =
39
+ useInputError(currentPassword, value =>
40
+ value.length < 6 ? 'Password must be at least 6 characters' : null,
41
+ );
42
+
43
+ const {error: newPasswordError, recheckValue: recheckNewPassword} =
44
+ useInputError(newPassword, value => {
45
+ if (value.length < 6) return 'Password must be at least 6 characters';
46
+ if (value === currentPassword)
47
+ return 'New password must be different from current password';
48
+ return null;
49
+ });
50
+
51
+ const {error: confirmPasswordError, recheckValue: recheckConfirmPassword} =
52
+ useInputError(confirmPassword, value =>
53
+ value !== newPassword ? 'Passwords do not match' : null,
54
+ );
55
+
56
+ async function handleChangePassword() {
57
+ const currentPasswordValid = recheckCurrentPassword() === null;
58
+ const newPasswordValid = recheckNewPassword() === null;
59
+ const confirmPasswordValid = recheckConfirmPassword() === null;
60
+
61
+ if (!currentPasswordValid || !newPasswordValid || !confirmPasswordValid) {
62
+ return;
63
+ }
64
+
65
+ setLoading(true);
66
+ try {
67
+ // Add your change password logic here
68
+ const response = await dispatch(
69
+ resetPassword({
70
+ mpin: currentPassword,
71
+ new_mpin: newPassword,
72
+ confirm_mpin: confirmPassword,
73
+ }),
74
+ );
75
+
76
+ if (resetPassword.fulfilled.match(response)) {
77
+ navigation.goBack();
78
+ }
79
+ } catch (error) {
80
+ console.error(error);
81
+ } finally {
82
+ setLoading(false);
83
+ }
84
+ }
85
+
86
+ return (
87
+ <Container
88
+ ref={scroll}
89
+ testID={'ForceChangePasswordID'}
90
+ contentContainerStyle={styles.contentContainer}
91
+ style={styles.container}
92
+ backgroundImage={ImageResources.background_2}
93
+ withoutPadding
94
+ extendedBackground
95
+ backgroundColor={theme.colors.background}>
96
+ <Header />
97
+ <RTLAwareText style={{...theme.text.body2, textAlign: 'center'}}>
98
+ {t('forceChange.subtitle', 'password')}
99
+ </RTLAwareText>
100
+ <PrimaryTextInput
101
+ label={t('forceChange.currentPassword', 'password')}
102
+ value={currentPassword}
103
+ onChangeText={setCurrentPassword}
104
+ error={currentPasswordError}
105
+ placeholder={t('forceChange.enterCurrentPassword', 'password')}
106
+ secureTextEntry={true}
107
+ keyboardType="numeric"
108
+ />
109
+ <PrimaryTextInput
110
+ label={t('forceChange.newPassword', 'password')}
111
+ value={newPassword}
112
+ onChangeText={setNewPassword}
113
+ error={newPasswordError}
114
+ placeholder={t('forceChange.enterNewPassword', 'password')}
115
+ secureTextEntry={true}
116
+ keyboardType="numeric"
117
+ />
118
+ <PrimaryTextInput
119
+ label={t('forceChange.confirmPassword', 'password')}
120
+ value={confirmPassword}
121
+ onChangeText={setConfirmPassword}
122
+ error={confirmPasswordError}
123
+ placeholder={t('forceChange.confirmNewPassword', 'password')}
124
+ secureTextEntry={true}
125
+ keyboardType="numeric"
126
+ />
127
+ <PrimaryButton
128
+ label={t('forceChange.changePassword', 'password')}
129
+ onPressIn={handleChangePassword}
130
+ isLoading={loading}
131
+ disabled={loading}
132
+ type={ButtonType.solid}
133
+ />
134
+ </Container>
135
+ );
136
+ }
137
+
138
+ const styles = StyleSheet.create({
139
+ container: {
140
+ flexGrow: 1,
141
+ borderTopRightRadius: CommonSizes.spacing.large,
142
+ borderTopLeftRadius: CommonSizes.spacing.large,
143
+ paddingHorizontal: CommonSizes.spacing.large,
144
+ justifyContent: 'flex-start',
145
+ gap: CommonSizes.spacing.large,
146
+ },
147
+ contentContainer: {
148
+ flexGrow: 1,
149
+ },
150
+ formContainer: {
151
+ width: '100%',
152
+ marginTop: CommonSizes.spacing.large,
153
+ gap: CommonSizes.spacing.medium,
154
+ },
155
+ });