@fadyshawky/react-native-magic 2.0.4 → 2.0.6

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 (80) hide show
  1. package/package.json +1 -1
  2. package/template/App.tsx +28 -19
  3. package/template/ios/reactnativemagic/AppDelegate.mm +5 -0
  4. package/template/src/common/components/Background.tsx +6 -4
  5. package/template/src/common/components/Container.tsx +6 -9
  6. package/template/src/common/components/OTPInput.tsx +3 -2
  7. package/template/src/common/components/PrimaryButton.tsx +23 -23
  8. package/template/src/common/components/PrimaryTextInput.tsx +189 -199
  9. package/template/src/common/components/RadioIcon.tsx +4 -4
  10. package/template/src/common/components/SafeText.tsx +41 -0
  11. package/template/src/common/components/SearchBar.tsx +19 -17
  12. package/template/src/common/components/TryAgain.tsx +3 -3
  13. package/template/src/common/localization/LocalizationProvider.tsx +14 -17
  14. package/template/src/common/localization/RTLInitializer.tsx +90 -0
  15. package/template/src/common/localization/localization.ts +8 -0
  16. package/template/src/common/localization/translations/commonLocalization.ts +33 -6
  17. package/template/src/common/localization/translations/emptyLocalization.ts +6 -2
  18. package/template/src/common/localization/translations/errorsLocalization.ts +33 -13
  19. package/template/src/common/localization/translations/homeLocalization.ts +6 -2
  20. package/template/src/common/localization/translations/loginLocalization.ts +32 -9
  21. package/template/src/common/localization/translations/mainNavigationLocalization.ts +30 -0
  22. package/template/src/common/localization/translations/navigationLocalization.ts +48 -0
  23. package/template/src/common/localization/translations/onboardingLocalization.ts +40 -9
  24. package/template/src/common/localization/translations/otpLocalization.ts +28 -0
  25. package/template/src/common/localization/translations/pagesLocalization.ts +13 -1
  26. package/template/src/common/localization/translations/passwordLocalization.ts +54 -0
  27. package/template/src/common/localization/translations/profileLocalization.ts +4 -4
  28. package/template/src/common/utils/FeesCaalculation.tsx +37 -0
  29. package/template/src/common/utils/index.tsx +11 -0
  30. package/template/src/common/utils/printData.tsx +161 -0
  31. package/template/src/common/validations/errorValidations.ts +3 -2
  32. package/template/src/core/api/serverHeaders.ts +62 -1
  33. package/template/src/core/store/Categories/categoryActions.ts +33 -0
  34. package/template/src/core/store/Categories/categorySlice.ts +75 -0
  35. package/template/src/core/store/Categories/categoryState.ts +41 -0
  36. package/template/src/core/store/Providers/providersActions.ts +102 -0
  37. package/template/src/core/store/Providers/providersSlice.ts +136 -0
  38. package/template/src/core/store/Providers/providersState.ts +37 -0
  39. package/template/src/core/store/Services/servicesActions.ts +191 -0
  40. package/template/src/core/store/Services/servicesSlice.ts +205 -0
  41. package/template/src/core/store/Services/servicesState.ts +466 -0
  42. package/template/src/core/store/app/appSlice.ts +13 -5
  43. package/template/src/core/store/app/appState.ts +10 -2
  44. package/template/src/core/store/rootReducer.ts +6 -1
  45. package/template/src/core/store/store.tsx +55 -2
  46. package/template/src/core/store/user/userActions.ts +164 -26
  47. package/template/src/core/store/user/userSlice.ts +193 -21
  48. package/template/src/core/store/user/userState.ts +148 -25
  49. package/template/src/core/theme/colors.ts +12 -0
  50. package/template/src/core/theme/themes.ts +1 -1
  51. package/template/src/core/utils/stringUtils.ts +114 -0
  52. package/template/src/navigation/AuthStack.tsx +8 -0
  53. package/template/src/navigation/HeaderComponents.tsx +52 -1
  54. package/template/src/navigation/MainNavigation.tsx +3 -1
  55. package/template/src/navigation/MainStack.tsx +39 -56
  56. package/template/src/navigation/TabBar.tsx +111 -59
  57. package/template/src/navigation/types.ts +24 -0
  58. package/template/src/screens/Login/Login.tsx +83 -85
  59. package/template/src/screens/OTP/OTPScreen.tsx +169 -0
  60. package/template/src/screens/home/Components/PayByCode.tsx +129 -0
  61. package/template/src/screens/home/HomeScreen.tsx +1 -103
  62. package/template/src/screens/home/hooks/useHomeData.ts +32 -38
  63. package/template/src/screens/index.tsx +24 -0
  64. package/template/src/common/components/Stepper.tsx +0 -153
  65. package/template/src/common/components/Svg.tsx +0 -25
  66. package/template/src/common/hooks/useDebounce.ts +0 -17
  67. package/template/src/common/hooks/usePrevious.ts +0 -11
  68. package/template/src/common/urls/emailUrl.ts +0 -20
  69. package/template/src/common/urls/mapUrl.ts +0 -22
  70. package/template/src/common/utils/listHandlers.ts +0 -30
  71. package/template/src/common/utils/serializeQueryParams.ts +0 -10
  72. package/template/src/common/validations/hooks/useDatesError.ts +0 -40
  73. package/template/src/common/validations/profileValidations.ts +0 -30
  74. package/template/src/navigation/TopTabBar.tsx +0 -77
  75. package/template/src/screens/Settings/Settings.tsx +0 -5
  76. package/template/src/screens/home/components/CarouselSection.tsx +0 -79
  77. package/template/src/screens/home/components/FeaturedCarousel.tsx +0 -128
  78. package/template/src/screens/main/Main.tsx +0 -5
  79. package/template/src/screens/registration/RegistrationScreen.tsx +0 -198
  80. package/template/src/screens/resetPassword/ForgotPasswordScreen.tsx +0 -129
@@ -1,44 +1,167 @@
1
1
  import {LoadState} from '../../../../types';
2
2
 
3
3
  export interface UserState {
4
- user: UserEntity;
4
+ user: User;
5
+ current_balance: number;
6
+ daily_commission: number;
5
7
  accessToken: string;
6
- loginLoading: LoadState;
8
+ loginLoading: string;
9
+ tempToken: string;
10
+ favoriteCategories: number[];
11
+ favoriteProviders: number[];
12
+ history: HistoryEntity[];
13
+ historyDetails: HistoryDetailsEntity[];
14
+ }
15
+ export interface User {
16
+ type: string;
17
+ mobile_number: string;
18
+ full_name: string;
19
+ merchantStore: MerchantStore;
20
+ status: string;
21
+ }
22
+ export interface MerchantStore {
23
+ id: number;
24
+ wallet_user_id: number;
25
+ name: string;
26
+ address: string;
27
+ city: string;
28
+ region: string;
29
+ store_imgs?: null;
30
+ tax_card?: null;
31
+ commercial_registration?: null;
32
+ createdAt: string;
33
+ updatedAt: string;
34
+ id_front: string;
35
+ id_back: string;
36
+ selfie?: null;
37
+ }
38
+ export interface HistoryEntity {
39
+ id: number;
40
+ transaction_reference_num: string;
41
+ bee_transaction_id?: null;
42
+ fawry_transaction_id?: string | null;
43
+ transaction_serial_num?: string | null;
44
+ amount: string | number;
45
+ sender_fees: string;
46
+ reciever_fees: string;
47
+ sender_identifier: string;
48
+ reciever_identifier: string;
49
+ status: string;
50
+ sender_status: string;
51
+ receiver_status: string;
52
+ reason?: null;
53
+ transactionReason: string;
54
+ display_reason?: null;
55
+ sender_interchange_amount: string;
56
+ receiver_interchange_amount: string;
57
+ sender_commission: string;
58
+ receiver_commission: string;
59
+ bulk_id?: null;
60
+ sender_name: string;
61
+ receiver_name: string;
62
+ notification_id?: null;
63
+ transaction_data?: null;
64
+ convenience: string;
65
+ tips: string;
66
+ reference1?: null;
67
+ reference2?: null;
68
+ meta?: null;
69
+ createdAt: string;
70
+ updatedAt: string;
71
+ transaction_type: number;
72
+ sender_id: number;
73
+ reciever_id: number;
74
+ sender_scheme_id: number;
75
+ receiver_scheme_id: number;
76
+ 'Transaction_type.id': number;
77
+ 'Transaction_type.name': string;
78
+ 'Transaction_type.name_ar'?: null;
79
+ 'Transaction_type.request_type': string;
80
+ 'Transaction_type.request_type_ar'?: null;
81
+ 'Transaction_type.timeout': string;
82
+ 'Transaction_type.on_off_us': string;
83
+ 'Transaction_type.sender_type': string;
84
+ 'Transaction_type.profile_type'?: null;
85
+ 'Transaction_type.receiver_type': string;
86
+ 'Transaction_type.tahweel_operation': string;
87
+ 'Transaction_type.send_fees'?: string | null;
88
+ 'Transaction_type.receive_fees': string;
89
+ 'Transaction_type.send_limit': string;
90
+ 'Transaction_type.receive_limit': string;
91
+ 'Transaction_type.send_commision'?: string | null;
92
+ 'Transaction_type.receive_commision'?: null;
93
+ 'Transaction_type.createdAt': string;
94
+ 'Transaction_type.updatedAt': string;
95
+ providerName?: string | null;
96
+ serviceName?: string | null;
97
+ totalAmount?: number | null;
98
+ }
99
+ export interface HistoryDetailsEntity {
100
+ value: string;
101
+ type: string;
102
+ label?: string;
103
+ }
104
+
105
+ export enum UserStatus {
106
+ ACTIVE = 'Active',
107
+ REGISTERED = 'Registered',
108
+ SUSPENDED = 'Suspended',
109
+ PENDING = 'Pending',
7
110
  }
8
111
 
9
112
  export interface UserPayload {
10
- user: UserEntity;
113
+ type: string;
114
+ mobile_number: string;
115
+ full_name: string;
116
+ merchantStore: MerchantStore;
117
+ requests: HistoryEntity[];
118
+ data: HistoryDetailsEntity[];
119
+ balance: {
120
+ name: string;
121
+ value: number;
122
+ }[];
123
+ current_balance: {
124
+ name: string;
125
+ value: number;
126
+ }[];
127
+ status: UserStatus;
128
+ fullname: string;
11
129
  token: string;
12
130
  }
13
131
 
14
132
  export const UserInitialState: UserState = {
15
133
  user: {
16
- id: 0,
17
- email: '',
18
- first_name: '',
19
- last_name: '',
20
- phone_number: '',
21
- address: '',
22
- role_id: 0,
23
- created_at: '',
24
- updated_at: '',
25
- deleted_at: null,
26
- roleName: '',
134
+ type: '',
135
+ mobile_number: '',
136
+ full_name: '',
137
+ status: UserStatus.PENDING,
138
+ merchantStore: {
139
+ id: 0,
140
+ wallet_user_id: 0,
141
+ name: '',
142
+ address: '',
143
+ city: '',
144
+ region: '',
145
+ createdAt: '',
146
+ updatedAt: '',
147
+ id_front: '',
148
+ id_back: '',
149
+ },
27
150
  },
151
+ current_balance: 0,
152
+ daily_commission: 0,
28
153
  accessToken: '',
29
154
  loginLoading: LoadState['needLoad'],
155
+ tempToken: '',
156
+ favoriteCategories: [],
157
+ favoriteProviders: [],
158
+ history: [],
159
+ historyDetails: [],
30
160
  };
31
161
 
32
162
  export interface UserEntity {
33
- id: number;
34
- email: string;
35
- first_name: string;
36
- last_name: string;
37
- phone_number: string;
38
- address: string;
39
- role_id: number;
40
- created_at: string;
41
- updated_at: string;
42
- deleted_at?: null;
43
- roleName: string;
163
+ type: string;
164
+ status: UserStatus;
165
+ mobile_number: string;
166
+ full_name: string;
44
167
  }
@@ -23,6 +23,7 @@ export enum PrimaryColors {
23
23
  }
24
24
 
25
25
  export enum NaturalColors {
26
+ background_2 = '#F9F9F9',
26
27
  grayScale_0 = '#FAFAFA',
27
28
  grayScale_25 = '#A3AAAD',
28
29
  grayScale_50 = '#949C9E',
@@ -97,3 +98,14 @@ export enum AlertColors {
97
98
  discover_600 = '#472661',
98
99
  discover_700 = '#2F1940',
99
100
  }
101
+
102
+ export enum BaseColors {
103
+ white = '#FFFFFF',
104
+ black = '#000000',
105
+ gray = '#808080',
106
+ red = '#FF0000',
107
+ green = '#00FF00',
108
+ blue = '#0000FF',
109
+ yellow = '#FFFF00',
110
+ purple = '#800080',
111
+ }
@@ -143,7 +143,7 @@ const commonTextStyles = {
143
143
  },
144
144
  button: {
145
145
  fontFamily: Fonts.regular,
146
- fontSize: CommonSizes.font.bodyXLarge,
146
+ fontSize: CommonSizes.font.bodyLarge,
147
147
  },
148
148
  cards: {
149
149
  fontFamily: Fonts.bold,
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Safely converts any value to a string
3
+ * This is especially useful for error messages that might be objects
4
+ */
5
+ import CryptoJS from 'crypto-js';
6
+
7
+ export const ensureString = (value: any): string => {
8
+ if (value === null || value === undefined) {
9
+ return '';
10
+ }
11
+
12
+ if (typeof value === 'string') {
13
+ return value;
14
+ }
15
+
16
+ if (typeof value === 'object') {
17
+ try {
18
+ // Try to extract a message property if it exists
19
+ if (value.message && typeof value.message === 'string') {
20
+ return value.message;
21
+ }
22
+
23
+ // Otherwise stringify the object
24
+ return JSON.stringify(value);
25
+ } catch (e) {
26
+ return '[Object]';
27
+ }
28
+ }
29
+
30
+ // For numbers, booleans, etc.
31
+ return String(value);
32
+ };
33
+
34
+ export function decryptTripleDES(
35
+ encryptedBase64: string,
36
+ secretKeyBase64: string,
37
+ ) {
38
+ try {
39
+ // Decode the key from base64
40
+ const decodedKey = CryptoJS.enc.Base64.parse(secretKeyBase64);
41
+
42
+ // Decode the encrypted value from base64
43
+ const encryptedWordArray = CryptoJS.enc.Base64.parse(encryptedBase64);
44
+
45
+ // Decrypt using Triple DES
46
+ const decrypted = CryptoJS.TripleDES.decrypt(
47
+ {ciphertext: encryptedWordArray},
48
+ decodedKey,
49
+ {
50
+ mode: CryptoJS.mode.ECB,
51
+ padding: CryptoJS.pad.Pkcs7,
52
+ },
53
+ );
54
+
55
+ let decryptedText = decrypted.toString(CryptoJS.enc.Utf8);
56
+
57
+ if (!decryptedText) {
58
+ throw new Error('Decryption resulted in empty string');
59
+ }
60
+
61
+ decryptedText = decryptedText.replace(/(.{4})/g, '$1-');
62
+ if (decryptedText.endsWith('-')) {
63
+ decryptedText = decryptedText.slice(0, -1);
64
+ }
65
+
66
+ return decryptedText;
67
+ } catch (error) {
68
+ throw new Error(`Decryption failed`);
69
+ }
70
+ }
71
+
72
+ // Example usage:
73
+ // const decrypted = decryptBase64('encrypted_base64_string', 'your_secret_key');
74
+
75
+ /**
76
+ * Converts a camelCase string to PascalCase with specific formatting
77
+ * Example: billerId -> BillerId
78
+ * @param str The camelCase string to convert
79
+ * @returns The converted PascalCase string
80
+ */
81
+ export const toPascalCase = (str: string): string => {
82
+ if (!str) return '';
83
+
84
+ // Split by capital letters and convert to array
85
+ const words = str.split(/(?=[A-Z])/);
86
+
87
+ // Capitalize first letter of each word and join
88
+ return words
89
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
90
+ .join('');
91
+ };
92
+
93
+ // Example usage:
94
+ // toPascalCase('billerId') => 'BillerId'
95
+ // toPascalCase('customerName') => 'CustomerName'
96
+ // toPascalCase('accountNumber') => 'AccountNumber'
97
+
98
+ /**
99
+ * Converts a PascalCase string to camelCase
100
+ * Example: BillerId -> billerId
101
+ * @param str The PascalCase string to convert
102
+ * @returns The converted camelCase string
103
+ */
104
+ export const toCamelCase = (str: string): string => {
105
+ if (!str) return '';
106
+
107
+ // Convert first character to lowercase and keep the rest as is
108
+ return str.charAt(0).toLowerCase() + str.slice(1);
109
+ };
110
+
111
+ // Example usage:
112
+ // toCamelCase('BillerId') => 'billerId'
113
+ // toCamelCase('CustomerName') => 'customerName'
114
+ // toCamelCase('AccountNumber') => 'accountNumber'
@@ -1,6 +1,7 @@
1
1
  import {createNativeStackNavigator} from '@react-navigation/native-stack';
2
2
  import {useTranslation} from '../common/localization/LocalizationProvider';
3
3
  import {Login} from '../screens/Login/Login';
4
+ import {OTPScreen} from '../screens/OTP/OTPScreen';
4
5
  import {Splash} from '../screens/splash/Splash';
5
6
 
6
7
  const Stack = createNativeStackNavigator();
@@ -23,6 +24,13 @@ export function AuthStack() {
23
24
  headerShown: false,
24
25
  },
25
26
  },
27
+ {
28
+ id: 'OTP',
29
+ component: OTPScreen,
30
+ options: {
31
+ headerShown: false,
32
+ },
33
+ },
26
34
  ];
27
35
 
28
36
  return (
@@ -1,18 +1,69 @@
1
+ import {NativeStackNavigationProp} from '@react-navigation/native-stack';
1
2
  import React from 'react';
2
- import {StyleSheet, View} from 'react-native';
3
+ import {Image, StyleSheet, TouchableOpacity, View} from 'react-native';
4
+ import {useRTL} from '../common/localization/LocalizationProvider';
3
5
  import {CommonSizes} from '../core/theme/commonSizes';
4
6
  import {screenWidth} from '../core/theme/commonStyles';
5
7
  import {scaleWidth} from '../core/theme/scaling';
8
+ import {useTheme} from '../core/theme/ThemeProvider';
9
+ import {RootStackParamList} from './types';
10
+ export function Header() {
11
+ return (
12
+ <View style={styles.headerBase}>
13
+ <Image source={0} style={styles.logo} />
14
+ </View>
15
+ );
16
+ }
17
+
18
+ export function HeaderBack({onPress}: {onPress: () => void}) {
19
+ return (
20
+ <View style={styles.headerWithBack}>
21
+ <BackButton onPress={onPress} />
22
+ <Image source={0} style={styles.logo} />
23
+ <View style={{width: 40}} />
24
+ </View>
25
+ );
26
+ }
6
27
 
7
28
  export function HeaderButton({onPress}: {onPress: () => void}) {
8
29
  return (
9
30
  <View style={styles.headerWithBack}>
31
+ <BackButton onPress={onPress} />
10
32
  <View style={styles.logo} />
11
33
  <View style={{width: 40}} />
12
34
  </View>
13
35
  );
14
36
  }
15
37
 
38
+ export function WebViewHeader({
39
+ navigation,
40
+ }: {
41
+ navigation: NativeStackNavigationProp<RootStackParamList>;
42
+ }) {
43
+ return (
44
+ <View style={styles.webViewHeader}>
45
+ {/* <BackButton navigation={navigation} /> */}
46
+ </View>
47
+ );
48
+ }
49
+
50
+ function BackButton({onPress}: {onPress: () => void}) {
51
+ const {theme} = useTheme();
52
+ const isRTL = useRTL();
53
+ return (
54
+ <TouchableOpacity style={styles.backButton} onPressIn={onPress}>
55
+ <Image
56
+ tintColor={theme.colors.PlatinateBlue_100}
57
+ style={{
58
+ ...styles.backIcon,
59
+ transform: [{rotate: isRTL ? '180deg' : '0deg'}],
60
+ }}
61
+ source={0}
62
+ />
63
+ </TouchableOpacity>
64
+ );
65
+ }
66
+
16
67
  const styles = StyleSheet.create({
17
68
  headerBase: {
18
69
  width: '100%',
@@ -7,6 +7,8 @@ import {useAppSelector} from '../core/store/reduxHelpers';
7
7
  import {AuthStack} from './AuthStack';
8
8
  import {AppMainNavigator} from './MainStack';
9
9
  import {navigationRef} from './RootNavigation';
10
+ import {NewColors} from '../core/theme/colors';
11
+ import {Fonts} from '../core/theme/fonts';
10
12
 
11
13
  function AppNavigator() {
12
14
  const routeNameRef = useRef<string | undefined>(undefined);
@@ -22,7 +24,7 @@ function AppNavigator() {
22
24
  dark: false,
23
25
  colors: {
24
26
  primary: '#000',
25
- background: 'white',
27
+ background: NewColors.background,
26
28
  card: '#fff',
27
29
  text: '#000',
28
30
  border: '#000',
@@ -1,52 +1,52 @@
1
1
  import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
2
- import {createNativeStackNavigator} from '@react-navigation/native-stack';
3
2
  import React from 'react';
3
+ import {useTranslation} from '../common/localization/LocalizationProvider';
4
+
5
+ import {createNativeStackNavigator} from '@react-navigation/native-stack';
6
+ import {Profile} from '../screens';
4
7
  import {HomeScreen} from '../screens/home/HomeScreen';
5
- import {Profile} from '../screens/profile/Profile';
6
- import {Settings} from '../screens/Settings/Settings';
7
8
  import {TabBar} from './TabBar';
8
9
 
9
- const MainScreens = [
10
- {
11
- id: 'Home',
12
- component: HomeScreen,
13
- options: {
14
- tabBarLabel: 'Profile',
15
- },
16
- },
17
- {
18
- id: 'Profile',
19
- component: Profile,
20
- options: {
21
- tabBarLabel: 'Profile',
22
- },
23
- },
24
- ];
25
-
26
- const AppStack = [
27
- {
28
- id: 'Main',
29
- component: MainTabs,
30
- options: {
31
- headerShown: false,
32
- },
33
- },
34
- {
35
- id: 'Settings',
36
- component: Settings,
37
- options: {},
38
- },
39
- ];
40
-
10
+ const Tab = createBottomTabNavigator();
41
11
  const Stack = createNativeStackNavigator();
42
12
 
43
- const Tab = createBottomTabNavigator();
13
+ export function AppMainNavigator() {
14
+ const t = useTranslation();
15
+
16
+ const MainScreens = [
17
+ {
18
+ id: 'Main',
19
+ component: HomeScreen,
20
+ options: {
21
+ tabBarLabel: t('tabs.Main', 'mainNavigation'),
22
+ headerShown: false,
23
+ icon: 0,
24
+ selectedIcon: 0,
25
+ },
26
+ },
27
+ {
28
+ id: 'Account',
29
+ component: Profile,
30
+ options: {
31
+ tabBarLabel: t('tabs.Account', 'mainNavigation'),
32
+ headerShown: false,
33
+ icon: 0,
34
+ selectedIcon: 0,
35
+ },
36
+ },
37
+ ];
44
38
 
45
- function MainTabs() {
46
39
  return (
47
40
  <Tab.Navigator
48
- initialRouteName="Home"
49
- tabBar={props => <TabBar {...props} />}>
41
+ initialRouteName="Main"
42
+ backBehavior="history"
43
+ detachInactiveScreens
44
+ tabBar={props => {
45
+ return <TabBar {...props} />;
46
+ }}
47
+ screenOptions={{
48
+ tabBarHideOnKeyboard: true,
49
+ }}>
50
50
  {MainScreens.map(s => (
51
51
  <Tab.Screen
52
52
  key={s.id}
@@ -58,20 +58,3 @@ function MainTabs() {
58
58
  </Tab.Navigator>
59
59
  );
60
60
  }
61
-
62
- export function AppMainNavigator() {
63
- return (
64
- <Stack.Navigator screenOptions={{animation: 'none'}}>
65
- {AppStack.map(s => {
66
- return (
67
- <Stack.Screen
68
- key={s.id}
69
- name={s.id}
70
- component={s.component}
71
- options={s.options}
72
- />
73
- );
74
- })}
75
- </Stack.Navigator>
76
- );
77
- }