@fadyshawky/react-native-magic 1.0.6 → 1.0.8
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.
- package/CHANGELOG.md +31 -1
- package/package.json +1 -1
- package/template/src/common/components/PrimaryButton.tsx +6 -6
- package/template/src/common/components/PrimaryTextInput.tsx +2 -2
- package/template/src/common/components/RadioIcon.tsx +4 -4
- package/template/src/common/components/TryAgain.tsx +2 -2
- package/template/src/common/localization/translations/homeLocalization.ts +1 -0
- package/template/src/core/store/user/userSlice.ts +1 -0
- package/template/src/navigation/MainNavigation.tsx +1 -18
- package/template/src/navigation/MainStack.tsx +7 -3
- package/template/src/navigation/TabBar.tsx +2 -2
- package/template/src/screens/Login/Login.tsx +3 -3
- package/template/src/screens/home/HomeScreen.tsx +107 -0
- package/template/src/screens/home/components/CarouselSection.tsx +80 -0
- package/template/src/screens/home/components/FeaturedCarousel.tsx +129 -0
- package/template/src/screens/home/hooks/useHomeData.ts +60 -0
- package/template/src/screens/home/types.ts +7 -0
- package/template/src/screens/registration/RegistrationScreen.tsx +2 -2
- package/template/src/screens/resetPassword/ForgotPasswordScreen.tsx +2 -2
- package/.vscode/settings.json +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## [1.0.
|
|
5
|
+
## [1.0.8] - 2024-01-24
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- Improved FeaturedCarousel component:
|
|
9
|
+
- Centered carousel items on screen
|
|
10
|
+
- Adjusted item width to 85% of screen width
|
|
11
|
+
- Added proper item layout calculations
|
|
12
|
+
- Enhanced snapping behavior
|
|
13
|
+
|
|
14
|
+
## [1.0.7] - 2024-12-27
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Enhanced UI components for better user experience:
|
|
18
|
+
- Improved form input styling
|
|
19
|
+
- Updated button states for better feedback
|
|
20
|
+
- Refined error message displays
|
|
21
|
+
- Added loading spinners for async actions
|
|
22
|
+
- Standardized form layouts across authentication flows
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
- Responsive design improvements for mobile devices
|
|
26
|
+
- Visual feedback for form validation states
|
|
27
|
+
- Transition animations for state changes
|
|
28
|
+
- Consistent error message styling
|
|
29
|
+
|
|
30
|
+
## [1.0.6] - 2024-12-25
|
|
6
31
|
|
|
7
32
|
### Added
|
|
8
33
|
- Added missing password reset handlers (`resetPasswordErrorHandler` and `resetPasswordLoadingHandler`) to user slice
|
|
@@ -17,6 +42,11 @@ All notable changes to this project will be documented in this file.
|
|
|
17
42
|
- Error handling for failed registration attempts
|
|
18
43
|
- Loading states during registration process
|
|
19
44
|
|
|
45
|
+
### Fixed
|
|
46
|
+
- Fixed password reset error handling in user slice
|
|
47
|
+
- Resolved undefined handler errors in password reset flow
|
|
48
|
+
- Improved registration flow error handling
|
|
49
|
+
|
|
20
50
|
## [1.0.5] - 2024-12-23
|
|
21
51
|
|
|
22
52
|
### Fixed
|
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
IIconPlatformProps,
|
|
17
17
|
TouchablePlatformProps,
|
|
18
18
|
} from '../../../types';
|
|
19
|
-
import {Colors} from '../../core/theme/colors';
|
|
19
|
+
import {Colors, NewColors} from '../../core/theme/colors';
|
|
20
20
|
import {CommonSizes} from '../../core/theme/commonSizes';
|
|
21
21
|
import {CommonStyles} from '../../core/theme/commonStyles';
|
|
22
22
|
import {IconPlatform} from './IconPlatform';
|
|
@@ -203,7 +203,7 @@ const commonIcon: ImageStyle = {
|
|
|
203
203
|
const solidStyles = StyleSheet.create({
|
|
204
204
|
button: {
|
|
205
205
|
...commonButtonStyle,
|
|
206
|
-
backgroundColor:
|
|
206
|
+
backgroundColor: NewColors.blueNormalActive,
|
|
207
207
|
} as ViewStyle,
|
|
208
208
|
label: {
|
|
209
209
|
...commonLabelStyle,
|
|
@@ -217,12 +217,12 @@ const solidStyles = StyleSheet.create({
|
|
|
217
217
|
const outlineStyles = StyleSheet.create({
|
|
218
218
|
button: {
|
|
219
219
|
...commonButtonStyle,
|
|
220
|
-
borderColor:
|
|
220
|
+
borderColor: NewColors.blueNormalActive,
|
|
221
221
|
borderWidth: 2,
|
|
222
222
|
} as ViewStyle,
|
|
223
223
|
label: {
|
|
224
224
|
...commonLabelStyle,
|
|
225
|
-
color:
|
|
225
|
+
color: NewColors.blueNormalActive,
|
|
226
226
|
} as TextStyle,
|
|
227
227
|
icon: {
|
|
228
228
|
...commonIcon,
|
|
@@ -255,7 +255,7 @@ const borderlessStyles = StyleSheet.create({
|
|
|
255
255
|
} as ViewStyle,
|
|
256
256
|
label: {
|
|
257
257
|
...commonLabelStyle,
|
|
258
|
-
color:
|
|
258
|
+
color: NewColors.blueNormalActive,
|
|
259
259
|
textDecorationLine: 'underline',
|
|
260
260
|
} as TextStyle,
|
|
261
261
|
icon: {
|
|
@@ -278,7 +278,7 @@ const roundedButtonStyle: ViewStyle = {
|
|
|
278
278
|
const smallSolidStyles = StyleSheet.create({
|
|
279
279
|
button: {
|
|
280
280
|
...roundedButtonStyle,
|
|
281
|
-
backgroundColor:
|
|
281
|
+
backgroundColor: NewColors.blueNormalActive,
|
|
282
282
|
} as ViewStyle,
|
|
283
283
|
label: {
|
|
284
284
|
...CommonStyles.normalText,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
View,
|
|
22
22
|
ViewStyle,
|
|
23
23
|
} from 'react-native';
|
|
24
|
-
import {Colors} from '../../core/theme/colors';
|
|
24
|
+
import {Colors, NewColors} from '../../core/theme/colors';
|
|
25
25
|
import {isIos} from '../../core/theme/commonConsts';
|
|
26
26
|
import {CommonSizes} from '../../core/theme/commonSizes';
|
|
27
27
|
import {CommonStyles} from '../../core/theme/commonStyles';
|
|
@@ -192,7 +192,7 @@ function getInputContainerStyle(
|
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
const selectionColor =
|
|
195
|
+
const selectionColor = NewColors.blueNormalActive;
|
|
196
196
|
|
|
197
197
|
const commonInputContainer: TextStyle = {
|
|
198
198
|
flexDirection: 'row',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, {FC, memo, useMemo} from 'react';
|
|
2
2
|
import {StyleSheet, View, ViewStyle} from 'react-native';
|
|
3
|
-
import {Colors} from '../../core/theme/colors';
|
|
3
|
+
import {Colors, NewColors} from '../../core/theme/colors';
|
|
4
4
|
|
|
5
5
|
interface IProps {
|
|
6
6
|
isSelected: boolean;
|
|
@@ -42,14 +42,14 @@ const commonInnerCircle: ViewStyle = {
|
|
|
42
42
|
const styles = StyleSheet.create({
|
|
43
43
|
outerCircle: {
|
|
44
44
|
...commonOuterCircle,
|
|
45
|
-
borderColor:
|
|
45
|
+
borderColor: NewColors.blueNormalActive,
|
|
46
46
|
} as ViewStyle,
|
|
47
47
|
outerCircleSelected: {
|
|
48
48
|
...commonOuterCircle,
|
|
49
|
-
borderColor:
|
|
49
|
+
borderColor: NewColors.blueNormalActive,
|
|
50
50
|
} as ViewStyle,
|
|
51
51
|
innerCircle: {
|
|
52
52
|
...commonInnerCircle,
|
|
53
|
-
backgroundColor:
|
|
53
|
+
backgroundColor: NewColors.blueNormalActive,
|
|
54
54
|
} as ViewStyle,
|
|
55
55
|
});
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
TouchableOpacity,
|
|
7
7
|
View,
|
|
8
8
|
} from 'react-native';
|
|
9
|
-
import {Colors} from '../../core/theme/colors';
|
|
9
|
+
import {Colors, NewColors} from '../../core/theme/colors';
|
|
10
10
|
import {CommonSizes} from '../../core/theme/commonSizes';
|
|
11
11
|
import {CommonStyles} from '../../core/theme/commonStyles';
|
|
12
12
|
import {localization} from '../localization/localization';
|
|
@@ -42,7 +42,7 @@ const styles = StyleSheet.create({
|
|
|
42
42
|
} as TextStyle,
|
|
43
43
|
description: {
|
|
44
44
|
...CommonStyles.normalText,
|
|
45
|
-
color:
|
|
45
|
+
color: NewColors.blueNormalActive,
|
|
46
46
|
textAlign: 'center',
|
|
47
47
|
textDecorationLine: 'underline',
|
|
48
48
|
} as TextStyle,
|
|
@@ -27,24 +27,7 @@ function AppNavigator() {
|
|
|
27
27
|
border: '#000',
|
|
28
28
|
notification: '#ff0000',
|
|
29
29
|
},
|
|
30
|
-
fonts:
|
|
31
|
-
regular: {
|
|
32
|
-
fontFamily: Fonts.regular,
|
|
33
|
-
fontWeight: 'normal',
|
|
34
|
-
},
|
|
35
|
-
medium: {
|
|
36
|
-
fontFamily: Fonts.medium,
|
|
37
|
-
fontWeight: '500',
|
|
38
|
-
},
|
|
39
|
-
bold: {
|
|
40
|
-
fontFamily: Fonts.bold,
|
|
41
|
-
fontWeight: '700',
|
|
42
|
-
},
|
|
43
|
-
heavy: {
|
|
44
|
-
fontFamily: Fonts.bold,
|
|
45
|
-
fontWeight: '900',
|
|
46
|
-
},
|
|
47
|
-
},
|
|
30
|
+
fonts: DefaultTheme.fonts,
|
|
48
31
|
}}
|
|
49
32
|
onReady={() => {
|
|
50
33
|
routeNameRef.current = navigationRef.current?.getCurrentRoute()?.name;
|
|
@@ -12,13 +12,17 @@ import {Settings} from '../screens/Settings/Settings';
|
|
|
12
12
|
import {Header, HeaderBack} from './HeaderComponents';
|
|
13
13
|
import {TabBar} from './TabBar';
|
|
14
14
|
import {RootStackParamList} from './types';
|
|
15
|
+
import {HomeScreen} from '../screens/home/HomeScreen';
|
|
15
16
|
|
|
16
17
|
const MainScreens = [
|
|
17
18
|
{
|
|
18
|
-
id: '
|
|
19
|
-
component:
|
|
19
|
+
id: 'Home',
|
|
20
|
+
component: HomeScreen,
|
|
20
21
|
options: {
|
|
21
|
-
|
|
22
|
+
tabBarLabel: 'Profile',
|
|
23
|
+
header: () => {
|
|
24
|
+
return <Header title={localization.home.home} />;
|
|
25
|
+
},
|
|
22
26
|
},
|
|
23
27
|
},
|
|
24
28
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import {View, Text, TouchableOpacity, Image, StyleSheet} from 'react-native';
|
|
3
3
|
import {CommonStyles} from '../core/theme/commonStyles';
|
|
4
|
-
import {Colors} from '../core/theme/colors';
|
|
4
|
+
import {Colors, NewColors} from '../core/theme/colors';
|
|
5
5
|
import {
|
|
6
6
|
BottomTabBarProps,
|
|
7
7
|
BottomTabNavigationOptions,
|
|
@@ -89,6 +89,6 @@ const styles = StyleSheet.create({
|
|
|
89
89
|
color: Colors.gray,
|
|
90
90
|
},
|
|
91
91
|
labelFocused: {
|
|
92
|
-
color:
|
|
92
|
+
color: NewColors.blueNormalActive,
|
|
93
93
|
},
|
|
94
94
|
});
|
|
@@ -19,7 +19,7 @@ import {useInputError} from '../../common/validations/hooks/useInputError';
|
|
|
19
19
|
import {emailValidations} from '../../common/validations/profileValidations';
|
|
20
20
|
import {useAppDispatch} from '../../core/store/reduxHelpers';
|
|
21
21
|
import {userLogin} from '../../core/store/user/userActions';
|
|
22
|
-
import {Colors} from '../../core/theme/colors';
|
|
22
|
+
import {Colors, NewColors} from '../../core/theme/colors';
|
|
23
23
|
import {CommonSizes} from '../../core/theme/commonSizes';
|
|
24
24
|
import {CommonStyles} from '../../core/theme/commonStyles';
|
|
25
25
|
import type {RootStackParamList} from '../../navigation/types';
|
|
@@ -151,14 +151,14 @@ const styles = StyleSheet.create({
|
|
|
151
151
|
},
|
|
152
152
|
forgotPassword: {
|
|
153
153
|
...CommonStyles.normalText,
|
|
154
|
-
color:
|
|
154
|
+
color: NewColors.blueNormalActive,
|
|
155
155
|
textAlign: 'right',
|
|
156
156
|
marginTop: 8,
|
|
157
157
|
marginBottom: 24,
|
|
158
158
|
},
|
|
159
159
|
registerLink: {
|
|
160
160
|
...CommonStyles.normalText,
|
|
161
|
-
color:
|
|
161
|
+
color: NewColors.blueNormalActive,
|
|
162
162
|
textAlign: 'center',
|
|
163
163
|
marginTop: 16,
|
|
164
164
|
},
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
ScrollView,
|
|
6
|
+
RefreshControl,
|
|
7
|
+
Dimensions,
|
|
8
|
+
Text,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
import {Colors} from '../../core/theme/colors';
|
|
11
|
+
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';
|
|
15
|
+
import {useHomeData} from './hooks/useHomeData';
|
|
16
|
+
|
|
17
|
+
const {width} = Dimensions.get('window');
|
|
18
|
+
|
|
19
|
+
export function HomeScreen(): JSX.Element {
|
|
20
|
+
const {
|
|
21
|
+
featuredItems,
|
|
22
|
+
trendingItems,
|
|
23
|
+
newItems,
|
|
24
|
+
recommendedItems,
|
|
25
|
+
isLoading,
|
|
26
|
+
refreshData,
|
|
27
|
+
} = useHomeData();
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<ScrollView
|
|
31
|
+
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}
|
|
48
|
+
/>
|
|
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}
|
|
57
|
+
/>
|
|
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}
|
|
66
|
+
/>
|
|
67
|
+
</View>
|
|
68
|
+
</View>
|
|
69
|
+
</ScrollView>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const styles = StyleSheet.create({
|
|
74
|
+
container: {
|
|
75
|
+
flex: 1,
|
|
76
|
+
backgroundColor: Colors.background,
|
|
77
|
+
},
|
|
78
|
+
content: {
|
|
79
|
+
paddingVertical: CommonSizes.spacing.medium,
|
|
80
|
+
},
|
|
81
|
+
featuredSection: {
|
|
82
|
+
marginBottom: CommonSizes.spacing.large,
|
|
83
|
+
},
|
|
84
|
+
carouselSection: {
|
|
85
|
+
marginBottom: CommonSizes.spacing.large,
|
|
86
|
+
},
|
|
87
|
+
sectionTitle: {
|
|
88
|
+
...CommonStyles.h2_semiBold,
|
|
89
|
+
marginHorizontal: CommonSizes.spacing.large,
|
|
90
|
+
marginBottom: CommonSizes.spacing.medium,
|
|
91
|
+
},
|
|
92
|
+
trendingImage: {
|
|
93
|
+
width: width * 0.7,
|
|
94
|
+
height: 200,
|
|
95
|
+
borderRadius: CommonSizes.borderRadius.medium,
|
|
96
|
+
},
|
|
97
|
+
newArrivalsImage: {
|
|
98
|
+
width: width * 0.5,
|
|
99
|
+
height: 180,
|
|
100
|
+
borderRadius: CommonSizes.borderRadius.medium,
|
|
101
|
+
},
|
|
102
|
+
recommendedImage: {
|
|
103
|
+
width: width * 0.6,
|
|
104
|
+
height: 160,
|
|
105
|
+
borderRadius: CommonSizes.borderRadius.medium,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
ScrollView,
|
|
6
|
+
Image,
|
|
7
|
+
TouchableOpacity,
|
|
8
|
+
ImageStyle,
|
|
9
|
+
Text,
|
|
10
|
+
} from 'react-native';
|
|
11
|
+
import {CommonSizes} from '../../../core/theme/commonSizes';
|
|
12
|
+
import {CommonStyles} from '../../../core/theme/commonStyles';
|
|
13
|
+
import {CarouselItem} from '../types';
|
|
14
|
+
import {Colors} from '../../../core/theme/colors';
|
|
15
|
+
|
|
16
|
+
interface CarouselSectionProps {
|
|
17
|
+
items: CarouselItem[];
|
|
18
|
+
imageStyle?: ImageStyle;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function CarouselSection({
|
|
22
|
+
items,
|
|
23
|
+
imageStyle,
|
|
24
|
+
}: CarouselSectionProps): JSX.Element {
|
|
25
|
+
return (
|
|
26
|
+
<ScrollView
|
|
27
|
+
horizontal
|
|
28
|
+
showsHorizontalScrollIndicator={false}
|
|
29
|
+
contentContainerStyle={styles.container}>
|
|
30
|
+
{items.map((item, index) => (
|
|
31
|
+
<TouchableOpacity
|
|
32
|
+
key={item.id}
|
|
33
|
+
style={styles.itemContainer}
|
|
34
|
+
onPress={() => item.onPress?.(item)}>
|
|
35
|
+
<Image
|
|
36
|
+
source={{uri: item.imageUrl}}
|
|
37
|
+
style={[styles.image, imageStyle]}
|
|
38
|
+
/>
|
|
39
|
+
<View style={styles.textContainer}>
|
|
40
|
+
<Text style={styles.title} numberOfLines={1}>
|
|
41
|
+
{item.title}
|
|
42
|
+
</Text>
|
|
43
|
+
{item.subtitle && (
|
|
44
|
+
<Text style={styles.subtitle} numberOfLines={1}>
|
|
45
|
+
{item.subtitle}
|
|
46
|
+
</Text>
|
|
47
|
+
)}
|
|
48
|
+
</View>
|
|
49
|
+
</TouchableOpacity>
|
|
50
|
+
))}
|
|
51
|
+
</ScrollView>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const styles = StyleSheet.create({
|
|
56
|
+
container: {
|
|
57
|
+
paddingHorizontal: CommonSizes.spacing.large,
|
|
58
|
+
},
|
|
59
|
+
itemContainer: {
|
|
60
|
+
marginRight: CommonSizes.spacing.medium,
|
|
61
|
+
},
|
|
62
|
+
image: {
|
|
63
|
+
width: 200,
|
|
64
|
+
height: 150,
|
|
65
|
+
borderRadius: CommonSizes.borderRadius.medium,
|
|
66
|
+
},
|
|
67
|
+
textContainer: {
|
|
68
|
+
marginTop: CommonSizes.spacing.small,
|
|
69
|
+
},
|
|
70
|
+
title: {
|
|
71
|
+
fontSize: 16,
|
|
72
|
+
fontWeight: '600',
|
|
73
|
+
color: Colors.blue100,
|
|
74
|
+
},
|
|
75
|
+
subtitle: {
|
|
76
|
+
fontSize: 14,
|
|
77
|
+
color: Colors.blue100,
|
|
78
|
+
marginTop: 2,
|
|
79
|
+
},
|
|
80
|
+
});
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import React, {useState, useRef} from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
Dimensions,
|
|
6
|
+
FlatList,
|
|
7
|
+
Image,
|
|
8
|
+
TouchableOpacity,
|
|
9
|
+
Text,
|
|
10
|
+
} from 'react-native';
|
|
11
|
+
import {Colors} from '../../../core/theme/colors';
|
|
12
|
+
import {CommonSizes} from '../../../core/theme/commonSizes';
|
|
13
|
+
import {CommonStyles} from '../../../core/theme/commonStyles';
|
|
14
|
+
import {CarouselItem} from '../types';
|
|
15
|
+
|
|
16
|
+
const {width} = Dimensions.get('window');
|
|
17
|
+
const ITEM_WIDTH = width * 0.85;
|
|
18
|
+
|
|
19
|
+
interface FeaturedCarouselProps {
|
|
20
|
+
items: CarouselItem[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function FeaturedCarousel({items}: FeaturedCarouselProps): JSX.Element {
|
|
24
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
25
|
+
const flatListRef = useRef<FlatList>(null);
|
|
26
|
+
|
|
27
|
+
const renderItem = ({item}: {item: CarouselItem}) => (
|
|
28
|
+
<TouchableOpacity
|
|
29
|
+
style={styles.itemContainer}
|
|
30
|
+
onPress={() => item.onPress?.(item)}>
|
|
31
|
+
<Image source={{uri: item.imageUrl}} style={styles.image} />
|
|
32
|
+
<View style={styles.overlay}>
|
|
33
|
+
<Text style={styles.title}>{item.title}</Text>
|
|
34
|
+
{item.subtitle && <Text style={styles.subtitle}>{item.subtitle}</Text>}
|
|
35
|
+
</View>
|
|
36
|
+
</TouchableOpacity>
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const renderDot = (index: number) => (
|
|
40
|
+
<View
|
|
41
|
+
key={index}
|
|
42
|
+
style={[styles.dot, index === activeIndex && styles.activeDot]}
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const handleScroll = (event: any) => {
|
|
47
|
+
const slideSize = event.nativeEvent.layoutMeasurement.width;
|
|
48
|
+
const index = event.nativeEvent.contentOffset.x / slideSize;
|
|
49
|
+
const roundIndex = Math.round(index);
|
|
50
|
+
setActiveIndex(roundIndex);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<View>
|
|
55
|
+
<FlatList
|
|
56
|
+
ref={flatListRef}
|
|
57
|
+
data={items}
|
|
58
|
+
renderItem={renderItem}
|
|
59
|
+
horizontal
|
|
60
|
+
pagingEnabled
|
|
61
|
+
showsHorizontalScrollIndicator={false}
|
|
62
|
+
onScroll={handleScroll}
|
|
63
|
+
snapToAlignment="center"
|
|
64
|
+
decelerationRate="fast"
|
|
65
|
+
snapToInterval={ITEM_WIDTH}
|
|
66
|
+
contentContainerStyle={styles.listContainer}
|
|
67
|
+
getItemLayout={(_, index) => ({
|
|
68
|
+
length: ITEM_WIDTH,
|
|
69
|
+
offset: ITEM_WIDTH * index,
|
|
70
|
+
index,
|
|
71
|
+
})}
|
|
72
|
+
/>
|
|
73
|
+
<View style={styles.pagination}>
|
|
74
|
+
{items.map((_, index) => renderDot(index))}
|
|
75
|
+
</View>
|
|
76
|
+
</View>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const styles = StyleSheet.create({
|
|
81
|
+
listContainer: {
|
|
82
|
+
paddingHorizontal: (width - ITEM_WIDTH) / 2,
|
|
83
|
+
},
|
|
84
|
+
itemContainer: {
|
|
85
|
+
width: ITEM_WIDTH,
|
|
86
|
+
height: 250,
|
|
87
|
+
},
|
|
88
|
+
image: {
|
|
89
|
+
width: '100%',
|
|
90
|
+
height: '100%',
|
|
91
|
+
borderRadius: CommonSizes.borderRadius.large,
|
|
92
|
+
},
|
|
93
|
+
overlay: {
|
|
94
|
+
...StyleSheet.absoluteFillObject,
|
|
95
|
+
backgroundColor: 'rgba(0, 0, 0, 0.3)',
|
|
96
|
+
borderRadius: CommonSizes.borderRadius.large,
|
|
97
|
+
padding: CommonSizes.spacing.large,
|
|
98
|
+
justifyContent: 'flex-end',
|
|
99
|
+
},
|
|
100
|
+
title: {
|
|
101
|
+
fontSize: 20,
|
|
102
|
+
fontWeight: '600',
|
|
103
|
+
color: Colors.white,
|
|
104
|
+
},
|
|
105
|
+
subtitle: {
|
|
106
|
+
fontSize: 16,
|
|
107
|
+
color: Colors.white,
|
|
108
|
+
marginTop: CommonSizes.spacing.small,
|
|
109
|
+
},
|
|
110
|
+
pagination: {
|
|
111
|
+
flexDirection: 'row',
|
|
112
|
+
justifyContent: 'center',
|
|
113
|
+
alignItems: 'center',
|
|
114
|
+
marginTop: CommonSizes.spacing.medium,
|
|
115
|
+
},
|
|
116
|
+
dot: {
|
|
117
|
+
width: 8,
|
|
118
|
+
height: 8,
|
|
119
|
+
borderRadius: 4,
|
|
120
|
+
backgroundColor: Colors.gray,
|
|
121
|
+
marginHorizontal: 4,
|
|
122
|
+
},
|
|
123
|
+
activeDot: {
|
|
124
|
+
backgroundColor: Colors.blue100,
|
|
125
|
+
width: 12,
|
|
126
|
+
height: 12,
|
|
127
|
+
borderRadius: 6,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {useState, useEffect} from 'react';
|
|
2
|
+
import {CarouselItem} from '../types';
|
|
3
|
+
|
|
4
|
+
export function useHomeData() {
|
|
5
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
6
|
+
const [featuredItems, setFeaturedItems] = useState<CarouselItem[]>([]);
|
|
7
|
+
const [trendingItems, setTrendingItems] = useState<CarouselItem[]>([]);
|
|
8
|
+
const [newItems, setNewItems] = useState<CarouselItem[]>([]);
|
|
9
|
+
const [recommendedItems, setRecommendedItems] = useState<CarouselItem[]>([]);
|
|
10
|
+
|
|
11
|
+
const fetchData = async () => {
|
|
12
|
+
setIsLoading(true);
|
|
13
|
+
try {
|
|
14
|
+
// Simulate API calls
|
|
15
|
+
// Replace with actual API calls in production
|
|
16
|
+
setFeaturedItems([
|
|
17
|
+
{
|
|
18
|
+
id: '1',
|
|
19
|
+
title: 'Featured Item 1',
|
|
20
|
+
subtitle: 'Discover amazing features',
|
|
21
|
+
imageUrl: 'https://picsum.photos/800/400',
|
|
22
|
+
},
|
|
23
|
+
// Add more items...
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
setTrendingItems([
|
|
27
|
+
{
|
|
28
|
+
id: '1',
|
|
29
|
+
title: 'Trending Item 1',
|
|
30
|
+
subtitle: 'Hot right now',
|
|
31
|
+
imageUrl: 'https://picsum.photos/700/400',
|
|
32
|
+
},
|
|
33
|
+
// Add more items...
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
// Similar for newItems and recommendedItems...
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error('Error fetching home data:', error);
|
|
39
|
+
} finally {
|
|
40
|
+
setIsLoading(false);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const refreshData = () => {
|
|
45
|
+
fetchData();
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
fetchData();
|
|
50
|
+
}, []);
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
isLoading,
|
|
54
|
+
featuredItems,
|
|
55
|
+
trendingItems,
|
|
56
|
+
newItems,
|
|
57
|
+
recommendedItems,
|
|
58
|
+
refreshData,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
} from '../../common/validations/profileValidations';
|
|
22
22
|
import {useAppDispatch} from '../../core/store/reduxHelpers';
|
|
23
23
|
import {userRegister} from '../../core/store/user/userActions';
|
|
24
|
-
import {Colors} from '../../core/theme/colors';
|
|
24
|
+
import {Colors, NewColors} from '../../core/theme/colors';
|
|
25
25
|
import {CommonSizes} from '../../core/theme/commonSizes';
|
|
26
26
|
import {CommonStyles} from '../../core/theme/commonStyles';
|
|
27
27
|
import type {RootStackParamList} from '../../navigation/types';
|
|
@@ -191,7 +191,7 @@ const styles = StyleSheet.create({
|
|
|
191
191
|
},
|
|
192
192
|
loginLink: {
|
|
193
193
|
...CommonStyles.normalText,
|
|
194
|
-
color:
|
|
194
|
+
color: NewColors.blueNormalActive,
|
|
195
195
|
textAlign: 'center',
|
|
196
196
|
marginTop: 16,
|
|
197
197
|
},
|
|
@@ -17,7 +17,7 @@ import {useInputError} from '../../common/validations/hooks/useInputError';
|
|
|
17
17
|
import {emailValidations} from '../../common/validations/profileValidations';
|
|
18
18
|
import {useAppDispatch} from '../../core/store/reduxHelpers';
|
|
19
19
|
import {resetPassword} from '../../core/store/user/userActions';
|
|
20
|
-
import {Colors} from '../../core/theme/colors';
|
|
20
|
+
import {Colors, NewColors} from '../../core/theme/colors';
|
|
21
21
|
import {CommonSizes} from '../../core/theme/commonSizes';
|
|
22
22
|
import {CommonStyles} from '../../core/theme/commonStyles';
|
|
23
23
|
import type {RootStackParamList} from '../../navigation/types';
|
|
@@ -122,7 +122,7 @@ const styles = StyleSheet.create({
|
|
|
122
122
|
},
|
|
123
123
|
loginLink: {
|
|
124
124
|
...CommonStyles.normalText,
|
|
125
|
-
color:
|
|
125
|
+
color: NewColors.blueNormalActive,
|
|
126
126
|
textAlign: 'center',
|
|
127
127
|
marginTop: 16,
|
|
128
128
|
},
|