@fadyshawky/react-native-magic 1.0.8 → 1.0.9

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 (60) hide show
  1. package/.vscode/settings.json +7 -0
  2. package/package.json +1 -1
  3. package/template/App.tsx +30 -9
  4. package/template/package-lock.json +170 -123
  5. package/template/package.json +1 -0
  6. package/template/src/common/ImageResources.g.ts +3 -5
  7. package/template/src/common/components/Background.tsx +66 -28
  8. package/template/src/common/components/Cards.tsx +116 -0
  9. package/template/src/common/components/Container.tsx +145 -0
  10. package/template/src/common/components/FlatListWrapper.tsx +1 -0
  11. package/template/src/common/components/ImageCropPickerButton.tsx +1 -1
  12. package/template/src/common/components/OTPInput.tsx +107 -0
  13. package/template/src/common/components/PhotoTakingButton.tsx +1 -4
  14. package/template/src/common/components/PrimaryButton.tsx +171 -157
  15. package/template/src/common/components/RTLAwareText.tsx +42 -0
  16. package/template/src/common/components/RTLAwareView.tsx +179 -0
  17. package/template/src/common/components/RadioButton.tsx +1 -3
  18. package/template/src/common/components/RadioIcon.tsx +1 -2
  19. package/template/src/common/components/SearchBar.tsx +179 -0
  20. package/template/src/common/components/Separator.tsx +7 -4
  21. package/template/src/common/components/TouchablePlatform.tsx +1 -3
  22. package/template/src/common/components/TryAgain.tsx +3 -3
  23. package/template/src/common/helpers/inAppReviewHelper.ts +0 -1
  24. package/template/src/common/helpers/stringsHelpers.ts +10 -0
  25. package/template/src/common/hooks/useFlatListActions.ts +1 -1
  26. package/template/src/common/localization/LocalizationProvider.tsx +152 -0
  27. package/template/src/common/localization/README.md +488 -0
  28. package/template/src/common/localization/localization.ts +12 -0
  29. package/template/src/common/localization/translations/profileLocalization.ts +24 -0
  30. package/template/src/common/validations/errorValidations.ts +1 -6
  31. package/template/src/common/validations/examples/TextInputWithValidation.tsx +229 -0
  32. package/template/src/common/validations/index.ts +28 -0
  33. package/template/src/common/validations/regex.js +83 -0
  34. package/template/src/common/validations/regexValidator.ts +240 -0
  35. package/template/src/common/validations/validationConstants.ts +2 -2
  36. package/template/src/core/api/errorHandler.ts +39 -0
  37. package/template/src/core/api/responseHandlers.ts +1 -26
  38. package/template/src/core/api/serverHeaders.ts +13 -23
  39. package/template/src/core/store/app/appSlice.ts +1 -2
  40. package/template/src/core/theme/ThemeProvider.tsx +63 -0
  41. package/template/src/core/theme/colors.ts +31 -42
  42. package/template/src/core/theme/commonConsts.ts +1 -1
  43. package/template/src/core/theme/commonStyles.ts +267 -210
  44. package/template/src/core/theme/fonts.ts +17 -1
  45. package/template/src/core/theme/scaling.ts +101 -0
  46. package/template/src/core/theme/themes.ts +214 -0
  47. package/template/src/core/theme/types.ts +51 -0
  48. package/template/src/navigation/AuthStack.tsx +25 -30
  49. package/template/src/navigation/HeaderComponents.tsx +18 -58
  50. package/template/src/navigation/MainNavigation.tsx +5 -6
  51. package/template/src/navigation/MainStack.tsx +3 -28
  52. package/template/src/navigation/RootNavigation.tsx +1 -7
  53. package/template/src/navigation/TabBar.tsx +2 -2
  54. package/template/src/navigation/TopTabBar.tsx +1 -1
  55. package/template/src/screens/Login/Login.tsx +3 -3
  56. package/template/src/screens/home/components/CarouselSection.tsx +7 -8
  57. package/template/src/screens/home/components/FeaturedCarousel.tsx +5 -6
  58. package/template/src/screens/registration/RegistrationScreen.tsx +2 -2
  59. package/template/src/screens/resetPassword/ForgotPasswordScreen.tsx +2 -2
  60. package/template/src/utils/stringBuilder.js +25 -0
@@ -19,6 +19,7 @@
19
19
  "test": "jest"
20
20
  },
21
21
  "dependencies": {
22
+ "@d11/react-native-fast-image": "^8.9.2",
22
23
  "@react-native-async-storage/async-storage": "^2.1.0",
23
24
  "@react-native-camera-roll/camera-roll": "^7.9.0",
24
25
  "@react-native-community/datetimepicker": "^8.2.0",
@@ -1,14 +1,12 @@
1
1
  /* eslint-disable */
2
2
  /* tslint:disable */
3
- import {ImageURISource} from "react-native";
3
+ import {ImageURISource} from 'react-native';
4
4
 
5
5
  /**
6
6
  * This file is auto-generated by react-native-image-resource-generator
7
7
  * !!! DO NOT EDIT !!!
8
8
  * For more information check the documentation:
9
9
  * https://github.com/svbutko/react-native-image-resource-generator
10
- */
10
+ */
11
11
 
12
- export class ImageResources {
13
-
14
- }
12
+ export class ImageResources {}
@@ -1,33 +1,71 @@
1
- import React from 'react';
2
- import {ImageBackground, StyleSheet, ViewStyle} from 'react-native';
3
- import {CommonStyles} from '../../core/theme/commonStyles';
1
+ import React, {FC, memo} from 'react';
2
+ import {ImageBackground, StyleSheet, View, ViewStyle} from 'react-native';
3
+ import {useTheme} from '../../core/theme/ThemeProvider';
4
+ import {ImageResources} from '../ImageResources.g';
5
+ import {Container} from './Container';
6
+ import {KeyboardAwareScrollViewProps} from 'react-native-keyboard-aware-scroll-view';
4
7
 
5
- interface BackgroundType {
8
+ interface BackgroundProps
9
+ extends Omit<KeyboardAwareScrollViewProps, 'contentContainerStyle'> {
6
10
  children: React.ReactNode;
7
- inverted?: boolean;
8
- extraStyle?: ViewStyle;
11
+ useSafeArea?: boolean;
12
+ style?: ViewStyle;
13
+ contentContainerStyle?: ViewStyle;
14
+ withoutPadding?: boolean;
15
+ withoutScroll?: boolean;
16
+ withoutBackgroundImage?: boolean;
9
17
  }
10
18
 
11
- export const Background = ({
12
- children,
13
- inverted,
14
- extraStyle,
15
- }: BackgroundType) => {
16
- const styles = StyleSheet.create({
17
- imageContainer: {
18
- ...CommonStyles.flex1,
19
- flexGrow: 1,
20
- // justifyContent: 'flex-end',
21
- },
22
- });
19
+ export const Background: FC<BackgroundProps> = memo(
20
+ ({
21
+ children,
22
+ useSafeArea = true,
23
+ style,
24
+ contentContainerStyle,
25
+ withoutPadding = false,
26
+ withoutScroll = false,
27
+ withoutBackgroundImage = false,
28
+ ...scrollViewProps
29
+ }) => {
30
+ const {theme} = useTheme();
23
31
 
24
- return (
25
- <ImageBackground
26
- resizeMode="cover"
27
- style={{...styles.imageContainer, ...extraStyle}}
28
- imageStyle={inverted ? {transform: [{rotateY: '180deg'}]} : undefined}
29
- source={0}>
30
- {children}
31
- </ImageBackground>
32
- );
33
- };
32
+ const content = (
33
+ <Container
34
+ useSafeArea={useSafeArea}
35
+ style={style}
36
+ contentContainerStyle={contentContainerStyle}
37
+ withoutPadding={withoutPadding}
38
+ withoutScroll={withoutScroll}
39
+ {...scrollViewProps}>
40
+ {children}
41
+ </Container>
42
+ );
43
+
44
+ if (withoutBackgroundImage) {
45
+ return (
46
+ <View
47
+ style={[
48
+ styles.container,
49
+ {backgroundColor: theme.colors.background},
50
+ ]}>
51
+ {content}
52
+ </View>
53
+ );
54
+ }
55
+
56
+ return (
57
+ <View
58
+ style={[styles.container, {backgroundColor: theme.colors.background}]}>
59
+ <ImageBackground source={0} style={styles.container}>
60
+ {content}
61
+ </ImageBackground>
62
+ </View>
63
+ );
64
+ },
65
+ );
66
+
67
+ const styles = StyleSheet.create({
68
+ container: {
69
+ flex: 1,
70
+ },
71
+ });
@@ -0,0 +1,116 @@
1
+ import React from 'react';
2
+ import {
3
+ Image,
4
+ StyleSheet,
5
+ Text,
6
+ TouchableOpacity,
7
+ View,
8
+ ViewStyle,
9
+ } from 'react-native';
10
+ import {CommonSizes} from '../../core/theme/commonSizes';
11
+ import {createThemedStyles} from '../../core/theme/commonStyles';
12
+ import {scaleHeight, scaleWidth} from '../../core/theme/scaling';
13
+ import {useTheme} from '../../core/theme/ThemeProvider';
14
+ import FastImage from '@d11/react-native-fast-image';
15
+
16
+ interface CardProps {
17
+ icon: {uri: string};
18
+ title: string;
19
+ onPress?: () => void;
20
+ marginRight?: number;
21
+ cardStyle?: ViewStyle;
22
+ }
23
+
24
+ export const Card = ({
25
+ icon,
26
+ title,
27
+ onPress,
28
+ marginRight,
29
+ cardStyle,
30
+ }: CardProps): JSX.Element => {
31
+ const {theme} = useTheme();
32
+ return (
33
+ <TouchableOpacity
34
+ style={[
35
+ styles.card,
36
+ {backgroundColor: theme.colors.surface},
37
+ createThemedStyles(theme).dropShadow,
38
+ {marginRight: marginRight},
39
+ {overflow: 'hidden'},
40
+ cardStyle,
41
+ ]}
42
+ onPress={() => {
43
+ onPress?.();
44
+ }}>
45
+ <View style={styles.iconContainer}>
46
+ {icon && icon.uri && (
47
+ <FastImage
48
+ source={{uri: icon.uri, cache: FastImage.cacheControl.immutable}}
49
+ style={{
50
+ width: '100%',
51
+ height: '100%',
52
+ }}
53
+ resizeMode={FastImage.resizeMode.contain}
54
+ />
55
+ )}
56
+ </View>
57
+ <Text style={[theme.text.cards, {textAlign: 'center'}]}>{title}</Text>
58
+ </TouchableOpacity>
59
+ );
60
+ };
61
+
62
+ const styles = StyleSheet.create({
63
+ card: {
64
+ padding: CommonSizes.spacing.medium,
65
+ borderRadius: CommonSizes.borderRadius.large,
66
+ alignItems: 'center',
67
+ justifyContent: 'flex-start',
68
+ gap: scaleHeight(10),
69
+ width: scaleWidth(187),
70
+ height: scaleHeight(280),
71
+ },
72
+ blurContainer: {
73
+ flex: 1,
74
+ padding: CommonSizes.spacing.medium,
75
+ alignItems: 'center',
76
+ justifyContent: 'center',
77
+ },
78
+ iconContainer: {
79
+ width: '100%',
80
+ height: scaleHeight(100),
81
+ },
82
+ title: {
83
+ fontSize: CommonSizes.fontSize.body2,
84
+ textAlign: 'center',
85
+ marginBottom: CommonSizes.spacing.small,
86
+ },
87
+ dotsContainer: {
88
+ flexDirection: 'row',
89
+ gap: 4,
90
+ },
91
+ dot: {
92
+ width: 4,
93
+ height: 4,
94
+ borderRadius: 2,
95
+ },
96
+ whiteDropShadow: {
97
+ // iOS shadow
98
+ shadowColor: '#FFF',
99
+ shadowOffset: {
100
+ width: 0,
101
+ height: 4,
102
+ },
103
+ shadowOpacity: 0.25,
104
+ shadowRadius: 8,
105
+ // Android shadow
106
+ elevation: 5,
107
+ // Add a very subtle border to enhance the white shadow effect
108
+ borderWidth: 0.5,
109
+ borderColor: 'rgba(255, 255, 255, 0.1)',
110
+ },
111
+ favoriteContainer: {
112
+ position: 'absolute',
113
+ top: scaleHeight(17),
114
+ left: scaleWidth(12),
115
+ },
116
+ });
@@ -0,0 +1,145 @@
1
+ import React, {forwardRef} from 'react';
2
+ import {
3
+ StyleSheet,
4
+ ViewStyle,
5
+ Platform,
6
+ KeyboardAvoidingView,
7
+ ScrollView,
8
+ View,
9
+ ImageBackground,
10
+ ImageSourcePropType,
11
+ } from 'react-native';
12
+ import {
13
+ KeyboardAwareScrollView,
14
+ KeyboardAwareScrollViewProps,
15
+ } from 'react-native-keyboard-aware-scroll-view';
16
+ import {useTheme} from '../../core/theme/ThemeProvider';
17
+ import {SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
18
+ import {ImageResources} from '../ImageResources.g';
19
+
20
+ interface ContainerProps extends Partial<KeyboardAwareScrollViewProps> {
21
+ children: React.ReactNode;
22
+ useSafeArea?: boolean;
23
+ style?: ViewStyle;
24
+ contentContainerStyle?: ViewStyle;
25
+ withoutPadding?: boolean;
26
+ withoutScroll?: boolean;
27
+ backgroundColor?: string;
28
+ withoutBackgroundImage?: boolean;
29
+ backgroundImage?: ImageSourcePropType;
30
+ extendedBackground?: boolean;
31
+ }
32
+
33
+ export const Container = forwardRef<KeyboardAwareScrollView, ContainerProps>(
34
+ (
35
+ {
36
+ children,
37
+ useSafeArea = true,
38
+ style,
39
+ contentContainerStyle,
40
+ withoutPadding = false,
41
+ withoutScroll = false,
42
+ backgroundColor,
43
+ withoutBackgroundImage = false,
44
+ backgroundImage = 0,
45
+ extendedBackground = false,
46
+ ...scrollViewProps
47
+ },
48
+ ref,
49
+ ) => {
50
+ const {theme} = useTheme();
51
+ const insets = useSafeAreaInsets();
52
+ const Wrapper = useSafeArea ? SafeAreaView : View;
53
+ const bgColor = backgroundColor || theme.colors.background;
54
+
55
+ const content = (
56
+ <Wrapper
57
+ style={[
58
+ styles.container,
59
+ !withoutPadding && styles.padding,
60
+ style,
61
+ extendedBackground && {
62
+ marginTop: -insets.top,
63
+ paddingTop: insets.top,
64
+ },
65
+ ]}>
66
+ {children}
67
+ </Wrapper>
68
+ );
69
+
70
+ const wrappedContent = withoutBackgroundImage ? (
71
+ <View style={[styles.container, {backgroundColor: bgColor}]}>
72
+ {content}
73
+ </View>
74
+ ) : (
75
+ <ImageBackground
76
+ source={backgroundImage}
77
+ style={[
78
+ styles.container,
79
+ extendedBackground && {
80
+ marginTop: -insets.top,
81
+ },
82
+ ]}
83
+ resizeMode="cover">
84
+ {content}
85
+ </ImageBackground>
86
+ );
87
+
88
+ if (withoutScroll) {
89
+ return (
90
+ <KeyboardAvoidingView
91
+ style={[
92
+ styles.container,
93
+ {backgroundColor: bgColor},
94
+ extendedBackground && {
95
+ marginTop: -insets.top,
96
+ },
97
+ ]}
98
+ behavior={undefined}
99
+ enabled>
100
+ {wrappedContent}
101
+ </KeyboardAvoidingView>
102
+ );
103
+ }
104
+
105
+ return (
106
+ <KeyboardAwareScrollView
107
+ ref={ref}
108
+ style={[
109
+ styles.container,
110
+ {backgroundColor: bgColor},
111
+ extendedBackground && {
112
+ marginTop: -insets.top,
113
+ },
114
+ ]}
115
+ contentContainerStyle={[
116
+ styles.contentContainer,
117
+ !withoutPadding && styles.padding,
118
+ contentContainerStyle,
119
+ ]}
120
+ keyboardShouldPersistTaps="handled"
121
+ showsVerticalScrollIndicator={false}
122
+ enableOnAndroid
123
+ enableResetScrollToCoords={false}
124
+ extraScrollHeight={20}
125
+ keyboardOpeningTime={0}
126
+ keyboardDismissMode="on-drag"
127
+ enableAutomaticScroll={true}
128
+ {...scrollViewProps}>
129
+ {wrappedContent}
130
+ </KeyboardAwareScrollView>
131
+ );
132
+ },
133
+ );
134
+
135
+ const styles = StyleSheet.create({
136
+ container: {
137
+ flex: 1,
138
+ },
139
+ contentContainer: {
140
+ flexGrow: 1,
141
+ },
142
+ padding: {
143
+ padding: 16, // Using a fixed value here as theme isn't available in StyleSheet
144
+ },
145
+ });
@@ -60,6 +60,7 @@ export function FlatListWrapper({
60
60
  {...props}
61
61
  refreshing={refreshing}
62
62
  ListEmptyComponent={ListEmptyComponent}
63
+ removeClippedSubviews={true}
63
64
  />
64
65
  );
65
66
  }
@@ -87,7 +87,7 @@ export const ImageCropPickerButton: FC<IProps> = memo(
87
87
  style={style}
88
88
  iconStyle={iconStyle}
89
89
  imageStyle={imageStyle}
90
- onPress={onPress}
90
+ onPressIn={onPress}
91
91
  backgroundImage={image}
92
92
  icon={icon}
93
93
  disabled={disabled}
@@ -0,0 +1,107 @@
1
+ import React, {useRef, useState} from 'react';
2
+ import {
3
+ NativeSyntheticEvent,
4
+ StyleSheet,
5
+ TextInput,
6
+ TextInputKeyPressEventData,
7
+ ViewStyle,
8
+ } from 'react-native';
9
+ import {useTheme} from '../../core/theme/ThemeProvider';
10
+ import {CommonSizes} from '../../core/theme/commonSizes';
11
+ import {scaleWidth} from '../../core/theme/scaling';
12
+ import {PrimaryTextInput} from './PrimaryTextInput';
13
+ import {RTLAwareView} from './RTLAwareView';
14
+
15
+ interface OTPInputProps {
16
+ value: string;
17
+ onChange: (value: string) => void;
18
+ error?: string | null;
19
+ style?: ViewStyle;
20
+ }
21
+
22
+ export const OTPInput: React.FC<OTPInputProps> = ({
23
+ value,
24
+ onChange,
25
+ error,
26
+ style,
27
+ }) => {
28
+ const {theme} = useTheme();
29
+ const inputRefs = useRef<Array<TextInput | null>>([]);
30
+ const [focused, setFocused] = useState<number>(-1);
31
+
32
+ const handleChange = (text: string, index: number) => {
33
+ const newValue = value.split('');
34
+ newValue[index] = text;
35
+ const finalValue = newValue.join('');
36
+ onChange(finalValue);
37
+
38
+ if (text.length > 0 && index < 5) {
39
+ inputRefs.current[index + 1]?.focus();
40
+ }
41
+ };
42
+
43
+ const handleKeyPress = (
44
+ e: NativeSyntheticEvent<TextInputKeyPressEventData>,
45
+ index: number,
46
+ ) => {
47
+ if (e.nativeEvent.key === 'Backspace' && index > 0 && !value[index]) {
48
+ inputRefs.current[index - 1]?.focus();
49
+ }
50
+ };
51
+
52
+ const handleFocus = (index: number) => {
53
+ setFocused(index);
54
+ };
55
+
56
+ const handleBlur = () => {
57
+ setFocused(-1);
58
+ };
59
+
60
+ return (
61
+ <RTLAwareView style={{...styles.container, ...style}}>
62
+ {[0, 1, 2, 3, 4, 5].map(index => (
63
+ <PrimaryTextInput
64
+ width={scaleWidth(78)}
65
+ key={index}
66
+ inputRef={ref => (inputRefs.current[index] = ref)}
67
+ style={[
68
+ styles.input,
69
+ {
70
+ borderColor: error
71
+ ? theme.colors.mutedLavender
72
+ : focused === index
73
+ ? theme.colors.indigoBlue
74
+ : theme.colors.mutedLavender30,
75
+ backgroundColor: theme.colors.backgroundOpacity,
76
+ },
77
+ ]}
78
+ maxLength={1}
79
+ keyboardType="number-pad"
80
+ value={value[index] || ''}
81
+ onChangeText={text => handleChange(text, index)}
82
+ onKeyPress={e => handleKeyPress(e, index)}
83
+ onFocus={() => handleFocus(index)}
84
+ onBlur={handleBlur}
85
+ selectTextOnFocus
86
+ />
87
+ ))}
88
+ </RTLAwareView>
89
+ );
90
+ };
91
+
92
+ const styles = StyleSheet.create({
93
+ container: {
94
+ flexDirection: 'row',
95
+ justifyContent: 'space-between',
96
+ width: '100%',
97
+ gap: CommonSizes.spacing.small,
98
+ paddingHorizontal: CommonSizes.spacing.large,
99
+ },
100
+ input: {
101
+ flex: 1,
102
+ height: CommonSizes.spacing.xxl,
103
+ borderWidth: 1,
104
+ borderRadius: CommonSizes.borderRadius.medium,
105
+ textAlign: 'center',
106
+ },
107
+ });
@@ -9,7 +9,6 @@ import {
9
9
  ViewStyle,
10
10
  } from 'react-native';
11
11
  import {Image as CropperImage} from 'react-native-image-crop-picker';
12
- import {Colors} from '../../core/theme/colors';
13
12
  import {CommonSizes} from '../../core/theme/commonSizes';
14
13
 
15
14
  interface IProps {
@@ -35,7 +34,7 @@ export const PhotoTakingButton: FC<IProps> = memo(
35
34
  return (
36
35
  <TouchableOpacity
37
36
  style={[styles.button, style]}
38
- onPress={onPress}
37
+ onPressIn={onPress}
39
38
  disabled={disabled}>
40
39
  <BackgroundComponent image={backgroundImage} style={imageStyle}>
41
40
  <Image style={[styles.icon, iconStyle]} source={icon!} />
@@ -76,7 +75,6 @@ const styles = StyleSheet.create({
76
75
  justifyContent: 'center',
77
76
  borderRadius: CommonSizes.borderRadius.small,
78
77
  borderWidth: 1,
79
- borderColor: Colors.gray,
80
78
  } as ViewStyle,
81
79
  image: {
82
80
  height: 120,
@@ -91,7 +89,6 @@ const styles = StyleSheet.create({
91
89
  width: 32,
92
90
  height: 32,
93
91
  resizeMode: 'contain',
94
- tintColor: Colors.black,
95
92
  opacity: 0.8,
96
93
  } as ImageStyle,
97
94
  });