create-gufran-expo-app 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.
- package/package.json +3 -3
- package/template/src/navigation/AuthStack.tsx +6 -25
- package/template/src/navigation/MainStack.tsx +0 -148
- package/template/src/navigation/RootNavigator.tsx +4 -26
- package/template/src/navigation/index.ts +0 -1
- package/template/src/navigation/navigationRef.ts +1 -1
- package/template/src/screens/HomeScreen.tsx +3 -215
- package/template/src/screens/auth/LoginScreen.tsx +13 -13
- package/template/src/screens/auth/index.ts +1 -6
- package/template/src/screens/index.ts +0 -35
- package/template/src/services/api.ts +5 -5
- package/template/src/services/authService.ts +3 -299
- package/template/src/services/mainServices.ts +19 -1914
- package/template/src/types/navigation.ts +5 -155
- package/template/src/utils/index.ts +5 -8
- package/template/src/navigation/MiddleStack.tsx +0 -35
- package/template/src/screens/auth/AddMamber.tsx +0 -428
- package/template/src/screens/auth/ForgotPasswordScreen.tsx +0 -176
- package/template/src/screens/auth/OTPVerifyScreen.tsx +0 -359
- package/template/src/screens/auth/RegisterScreen.tsx +0 -430
- package/template/src/screens/auth/SuccessScreen.tsx +0 -201
- package/template/src/screens/chat/ChatScreen.tsx +0 -1819
- package/template/src/screens/chat/ChatThreadsScreen.tsx +0 -360
- package/template/src/screens/chat/ReportMessageScreen.tsx +0 -238
- package/template/src/screens/clubs/Announcements.tsx +0 -426
- package/template/src/screens/clubs/BuyRaffleTicketsScreen.tsx +0 -568
- package/template/src/screens/clubs/ClubDeteils.tsx +0 -497
- package/template/src/screens/clubs/JoinClub.tsx +0 -841
- package/template/src/screens/events/EventScreen.tsx +0 -460
- package/template/src/screens/raffles/MyReferralMembersScreen.tsx +0 -758
- package/template/src/screens/raffles/RaffleDetailsScreen.tsx +0 -762
- package/template/src/screens/raffles/RafflesScreen.tsx +0 -495
- package/template/src/screens/raffles/SetRaffleReminderScreen.tsx +0 -390
- package/template/src/screens/teams/JoinTeamScreen.tsx +0 -464
- package/template/src/screens/teams/MyTeamDetailsScreen.tsx +0 -979
- package/template/src/screens/teams/MyTeamScreen.tsx +0 -568
- package/template/src/screens/teams/PendingRequestsScreen.tsx +0 -426
- package/template/src/screens/volunteerOpportunities/SetReminderScreen.tsx +0 -631
- package/template/src/screens/volunteerOpportunities/VolunteerOpportunitiesDetailsScreen.tsx +0 -1049
- package/template/src/screens/volunteerOpportunities/VolunteerOpportunitiesScreen.tsx +0 -608
- package/template/src/utils/ClubSearchManager.ts +0 -222
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-gufran-expo-app",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"description": "🚀 Ultimate Expo React Native Boilerplate - Create production-ready Expo apps instantly with Firebase, Navigation, TypeScript, and more. No git clone needed, works offline!",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"starter-kit",
|
|
23
23
|
"gufran"
|
|
24
24
|
],
|
|
25
|
-
"author": "Gufran Gaury <
|
|
25
|
+
"author": "Gufran Gaury <gufran.gaury@gmail.com>",
|
|
26
26
|
"license": "MIT",
|
|
27
27
|
"repository": {
|
|
28
28
|
"type": "git",
|
|
@@ -49,4 +49,4 @@
|
|
|
49
49
|
"README.md",
|
|
50
50
|
"LICENSE"
|
|
51
51
|
]
|
|
52
|
-
}
|
|
52
|
+
}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
|
3
3
|
import { AuthStackParamList } from '../types';
|
|
4
|
-
import { LoginScreen,
|
|
5
|
-
import { theme } from '
|
|
6
|
-
import { StorageService } from '
|
|
7
|
-
import SuccessScreen from '../screens/auth/SuccessScreen';
|
|
4
|
+
import { LoginScreen, WelcomeScreen } from '../screens/auth';
|
|
5
|
+
import { theme } from '@constants';
|
|
6
|
+
import { StorageService } from '@utils/storage';
|
|
8
7
|
|
|
9
8
|
const Stack = createNativeStackNavigator<AuthStackParamList>();
|
|
10
9
|
|
|
11
10
|
export const AuthStack: React.FC = () => {
|
|
12
11
|
// Check if welcome screen has been shown before
|
|
13
12
|
const hasWelcomeScreenBeenShown = StorageService.preferences.getWelcomeScreenShown();
|
|
14
|
-
|
|
13
|
+
|
|
15
14
|
// Set initial route based on whether welcome screen has been shown
|
|
16
15
|
const initialRouteName = hasWelcomeScreenBeenShown ? 'Login' : 'Welcome';
|
|
17
16
|
|
|
@@ -37,30 +36,12 @@ export const AuthStack: React.FC = () => {
|
|
|
37
36
|
<Stack.Screen
|
|
38
37
|
name="Welcome"
|
|
39
38
|
component={WelcomeScreen}
|
|
40
|
-
|
|
39
|
+
|
|
41
40
|
/>
|
|
42
41
|
<Stack.Screen
|
|
43
42
|
name="Login"
|
|
44
43
|
component={LoginScreen}
|
|
45
|
-
|
|
46
|
-
/>
|
|
47
|
-
<Stack.Screen
|
|
48
|
-
name="Register"
|
|
49
|
-
component={RegisterScreen}
|
|
50
|
-
|
|
51
|
-
/>
|
|
52
|
-
<Stack.Screen
|
|
53
|
-
name="ForgotPassword"
|
|
54
|
-
component={ForgotPasswordScreen}
|
|
55
|
-
|
|
56
|
-
/>
|
|
57
|
-
<Stack.Screen
|
|
58
|
-
name="OTPVerify"
|
|
59
|
-
component={OTPVerifyScreen}
|
|
60
|
-
/>
|
|
61
|
-
<Stack.Screen
|
|
62
|
-
name="Success"
|
|
63
|
-
component={SuccessScreen}
|
|
44
|
+
|
|
64
45
|
/>
|
|
65
46
|
</Stack.Navigator>
|
|
66
47
|
);
|
|
@@ -3,30 +3,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
|
|
3
3
|
import { MainStackParamList } from '../types';
|
|
4
4
|
import {
|
|
5
5
|
HomeScreen,
|
|
6
|
-
ProfileScreen,
|
|
7
|
-
SettingsScreen,
|
|
8
|
-
DetailsScreen,
|
|
9
|
-
ClubDetailsScreen,
|
|
10
|
-
SportHubScreen,
|
|
11
|
-
MyTeamScreen,
|
|
12
|
-
MyTeamDetailsScreen,
|
|
13
|
-
JoinTeam,
|
|
14
|
-
ChatThreadsScreen,
|
|
15
|
-
ChatScreen,
|
|
16
|
-
ReportMessageScreen,
|
|
17
|
-
Announcements,
|
|
18
|
-
VolunteerOpportunitiesScreen,
|
|
19
|
-
RafflesScreen,
|
|
20
|
-
RaffleDetailsScreen,
|
|
21
|
-
BuyRaffleTicketsScreen,
|
|
22
|
-
VolunteerOpportunitiesDetailsScreen,
|
|
23
|
-
MyReferralMembersScreen,
|
|
24
|
-
SetReminderScreen,
|
|
25
|
-
SetRaffleReminderScreen,
|
|
26
|
-
EventScreen
|
|
27
6
|
} from '../screens';
|
|
28
|
-
import { PendingRequestsScreen } from '../screens/teams/PendingRequestsScreen';
|
|
29
|
-
import { JoinClubScreen } from '../screens/clubs/JoinClub';
|
|
30
7
|
import { theme } from '../constants/theme';
|
|
31
8
|
|
|
32
9
|
const Stack = createNativeStackNavigator<MainStackParamList>();
|
|
@@ -52,132 +29,7 @@ export const MainStack: React.FC = () => {
|
|
|
52
29
|
}}
|
|
53
30
|
>
|
|
54
31
|
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Club Yakka', headerLargeTitle: true }} />
|
|
55
|
-
<Stack.Screen name="Profile" component={ProfileScreen} options={{ title: 'Profile', headerBackTitle: 'Back' }} />
|
|
56
|
-
<Stack.Screen
|
|
57
|
-
name="Settings"
|
|
58
|
-
component={SettingsScreen}
|
|
59
|
-
options={{
|
|
60
|
-
title: 'Settings',
|
|
61
|
-
headerBackTitle: 'Back',
|
|
62
|
-
}}
|
|
63
|
-
/>
|
|
64
|
-
<Stack.Screen
|
|
65
|
-
name="Details"
|
|
66
|
-
component={DetailsScreen}
|
|
67
|
-
options={({ route }) => ({
|
|
68
|
-
title: route.params?.title || 'Details',
|
|
69
|
-
headerBackTitle: 'Back',
|
|
70
|
-
})}
|
|
71
|
-
/>
|
|
72
|
-
<Stack.Screen
|
|
73
|
-
name="JoinClub"
|
|
74
|
-
component={JoinClubScreen}
|
|
75
|
-
options={{
|
|
76
|
-
title: 'Join Club',
|
|
77
|
-
headerBackTitle: 'Back',
|
|
78
|
-
}}
|
|
79
|
-
/>
|
|
80
32
|
|
|
81
|
-
<Stack.Screen
|
|
82
|
-
name="ClubDetails"
|
|
83
|
-
component={ClubDetailsScreen}
|
|
84
|
-
options={{
|
|
85
|
-
title: 'Club Details',
|
|
86
|
-
headerBackTitle: 'Back',
|
|
87
|
-
}}
|
|
88
|
-
/>
|
|
89
|
-
<Stack.Screen
|
|
90
|
-
name="SportHub"
|
|
91
|
-
component={SportHubScreen}
|
|
92
|
-
options={{
|
|
93
|
-
title: 'MY SPORT HUB',
|
|
94
|
-
headerBackTitle: 'Back',
|
|
95
|
-
}}
|
|
96
|
-
/>
|
|
97
|
-
<Stack.Screen
|
|
98
|
-
name="MyTeam"
|
|
99
|
-
component={MyTeamScreen}
|
|
100
|
-
/>
|
|
101
|
-
<Stack.Screen
|
|
102
|
-
name="MyTeamDetails"
|
|
103
|
-
component={MyTeamDetailsScreen}
|
|
104
|
-
options={{
|
|
105
|
-
title: 'Team Details',
|
|
106
|
-
headerBackTitle: 'Back',
|
|
107
|
-
}}
|
|
108
|
-
/>
|
|
109
|
-
<Stack.Screen
|
|
110
|
-
name="PendingRequests"
|
|
111
|
-
component={PendingRequestsScreen}
|
|
112
|
-
options={{
|
|
113
|
-
title: 'Pending Requests',
|
|
114
|
-
headerBackTitle: 'Back',
|
|
115
|
-
}}
|
|
116
|
-
/>
|
|
117
|
-
<Stack.Screen
|
|
118
|
-
name="JoinTeam"
|
|
119
|
-
component={JoinTeam}
|
|
120
|
-
/>
|
|
121
|
-
|
|
122
|
-
<Stack.Screen
|
|
123
|
-
name="ChatThreads"
|
|
124
|
-
component={ChatThreadsScreen}
|
|
125
|
-
/>
|
|
126
|
-
<Stack.Screen
|
|
127
|
-
name="ChatScreen"
|
|
128
|
-
component={ChatScreen}
|
|
129
|
-
/>
|
|
130
|
-
<Stack.Screen
|
|
131
|
-
name="ReportMessage"
|
|
132
|
-
component={ReportMessageScreen}
|
|
133
|
-
options={{
|
|
134
|
-
presentation: 'transparentModal',
|
|
135
|
-
headerShown: false,
|
|
136
|
-
animation: 'fade',
|
|
137
|
-
}}
|
|
138
|
-
/>
|
|
139
|
-
<Stack.Screen
|
|
140
|
-
name="Announcements"
|
|
141
|
-
component={Announcements}
|
|
142
|
-
/>
|
|
143
|
-
<Stack.Screen
|
|
144
|
-
name="VolunteerOpportunitiesScreen"
|
|
145
|
-
component={VolunteerOpportunitiesScreen}
|
|
146
|
-
/>
|
|
147
|
-
<Stack.Screen
|
|
148
|
-
name="VolunteerOpportunitiesDetailsScreen"
|
|
149
|
-
component={VolunteerOpportunitiesDetailsScreen}
|
|
150
|
-
/>
|
|
151
|
-
<Stack.Screen
|
|
152
|
-
name="Raffles"
|
|
153
|
-
component={RafflesScreen}
|
|
154
|
-
/>
|
|
155
|
-
<Stack.Screen
|
|
156
|
-
name="RaffleDetails"
|
|
157
|
-
component={RaffleDetailsScreen}
|
|
158
|
-
/>
|
|
159
|
-
<Stack.Screen
|
|
160
|
-
name="BuyRaffleTickets"
|
|
161
|
-
component={BuyRaffleTicketsScreen}
|
|
162
|
-
/>
|
|
163
|
-
<Stack.Screen
|
|
164
|
-
name="MyReferralMembers"
|
|
165
|
-
component={MyReferralMembersScreen}
|
|
166
|
-
/>
|
|
167
|
-
<Stack.Screen
|
|
168
|
-
name="SetReminder"
|
|
169
|
-
component={SetReminderScreen}
|
|
170
|
-
/>
|
|
171
|
-
<Stack.Screen
|
|
172
|
-
name="SetRaffleReminder"
|
|
173
|
-
component={SetRaffleReminderScreen}
|
|
174
|
-
/>
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
<Stack.Screen
|
|
178
|
-
name="EventScreen"
|
|
179
|
-
component={EventScreen}
|
|
180
|
-
/>
|
|
181
33
|
</Stack.Navigator>
|
|
182
34
|
);
|
|
183
35
|
};
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import React, { useEffect } from 'react';
|
|
2
2
|
import { NavigationContainer } from '@react-navigation/native';
|
|
3
|
-
import { useAuthStore } from '
|
|
3
|
+
import { useAuthStore } from '@stores/authStore';
|
|
4
4
|
import { AuthStack } from './AuthStack';
|
|
5
|
-
import { MiddleStack } from './MiddleStack';
|
|
6
5
|
import { MainStack } from './MainStack';
|
|
7
|
-
import { LoadingSpinner } from '
|
|
6
|
+
import { LoadingSpinner } from '@components/common';
|
|
8
7
|
import * as SplashScreen from 'expo-splash-screen';
|
|
9
8
|
import { navigationRef } from './navigationRef';
|
|
10
|
-
import NotificationManager from '
|
|
9
|
+
import NotificationManager from '@utils/NotificationManager';
|
|
11
10
|
|
|
12
11
|
// Navigation component that switches between Auth, Middle and Main stacks
|
|
13
12
|
const AppNavigator: React.FC = () => {
|
|
14
13
|
const isLoading = useAuthStore((state) => state.isLoading);
|
|
15
14
|
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
|
16
|
-
const user = useAuthStore((state) => state.user);
|
|
17
15
|
|
|
18
16
|
if (isLoading) {
|
|
19
17
|
return <LoadingSpinner />;
|
|
@@ -23,11 +21,6 @@ const AppNavigator: React.FC = () => {
|
|
|
23
21
|
return <AuthStack />;
|
|
24
22
|
}
|
|
25
23
|
|
|
26
|
-
// If user is authenticated but needs to add member, show MiddleStack
|
|
27
|
-
if (user?.isAddMember) {
|
|
28
|
-
return <MiddleStack />;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
24
|
// Otherwise show MainStack
|
|
32
25
|
return <MainStack />;
|
|
33
26
|
};
|
|
@@ -70,23 +63,8 @@ export const RootNavigator: React.FC = () => {
|
|
|
70
63
|
};
|
|
71
64
|
}, []);
|
|
72
65
|
|
|
73
|
-
// When authentication state changes to a stack that contains the target routes,
|
|
74
|
-
// attempt any pending navigation that may have been queued from a notification.
|
|
75
|
-
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
|
76
|
-
const user = useAuthStore((state) => state.user);
|
|
77
|
-
useEffect(() => {
|
|
78
|
-
// Only try when we are in the main app (not auth / middle stack)
|
|
79
|
-
if (isAuthenticated && !user?.isAddMember) {
|
|
80
|
-
// Small delay to ensure navigator screens are mounted
|
|
81
|
-
const id = setTimeout(() => {
|
|
82
|
-
NotificationManager.executePendingNavigation();
|
|
83
|
-
}, 100);
|
|
84
|
-
return () => clearTimeout(id);
|
|
85
|
-
}
|
|
86
|
-
}, [isAuthenticated, user?.isAddMember]);
|
|
87
|
-
|
|
88
66
|
return (
|
|
89
|
-
<NavigationContainer
|
|
67
|
+
<NavigationContainer
|
|
90
68
|
ref={navigationRef}
|
|
91
69
|
onReady={() => {
|
|
92
70
|
setTimeout(() => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createNavigationContainerRef } from '@react-navigation/native';
|
|
2
|
-
import { RootStackParamList } from '
|
|
2
|
+
import { RootStackParamList } from '@navigation';
|
|
3
3
|
|
|
4
4
|
// Create navigation reference
|
|
5
5
|
export const navigationRef = createNavigationContainerRef<RootStackParamList>();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { useState, useEffect, useCallback
|
|
2
|
-
import { View, Text, StyleSheet, FlatList, StatusBar, Platform, TouchableOpacity, Image, RefreshControl, ActivityIndicator,
|
|
1
|
+
import React, { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet, FlatList, StatusBar, Platform, TouchableOpacity, Image, RefreshControl, ActivityIndicator, Alert } from 'react-native';
|
|
3
3
|
import { useQueryClient } from '@tanstack/react-query';
|
|
4
4
|
import { useFocusEffect } from '@react-navigation/native';
|
|
5
5
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
@@ -11,64 +11,19 @@ import { Fonts } from '@constants/Fonts';
|
|
|
11
11
|
import { useAuthStore } from '@stores/authStore';
|
|
12
12
|
import { getApiErrorInfo, useLogout } from '@services/authService';
|
|
13
13
|
import { Button, ClubCard } from '@components/common';
|
|
14
|
-
import {
|
|
14
|
+
import { useInfiniteMyClubs } from '@services/mainServices';
|
|
15
15
|
import ToastManager from '@components/common/ToastManager';
|
|
16
16
|
import SVG from '@assets/icons';
|
|
17
17
|
|
|
18
|
-
type MemberListItemProps = {
|
|
19
|
-
item: any;
|
|
20
|
-
isSelected: boolean;
|
|
21
|
-
onSelect: (member: any) => void;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
18
|
|
|
25
|
-
const MemberListItem: React.FC<MemberListItemProps> = ({ item, isSelected, onSelect }) => {
|
|
26
|
-
const [memberImageError, setMemberImageError] = useState(false);
|
|
27
|
-
return (
|
|
28
|
-
<TouchableOpacity style={styles.memberListItem} onPress={() => onSelect(item)}>
|
|
29
|
-
{item?.profileImage && !memberImageError ? (
|
|
30
|
-
<Image
|
|
31
|
-
source={{ uri: item?.profileImage }}
|
|
32
|
-
onError={() => {
|
|
33
|
-
setMemberImageError(true);
|
|
34
|
-
}}
|
|
35
|
-
style={styles.profileImage}
|
|
36
|
-
/>
|
|
37
|
-
) : (
|
|
38
|
-
<SVG.emptyUser style={{ marginRight: moderateScale(10) }} width={moderateScale(50)} height={moderateScale(50)} />
|
|
39
|
-
)}
|
|
40
|
-
<View style={styles.memberNameContainer}>
|
|
41
|
-
<Text style={styles.memberName}>{item?.name}</Text>
|
|
42
|
-
{item?.isOwner && (
|
|
43
|
-
<Text style={styles.memberNameSubtitle}>Yourself</Text>
|
|
44
|
-
)}
|
|
45
|
-
</View>
|
|
46
|
-
<View>
|
|
47
|
-
{isSelected ? (
|
|
48
|
-
<SVG.checkRadio width={moderateScale(20)} height={moderateScale(20)} />
|
|
49
|
-
) : (
|
|
50
|
-
<SVG.uncheckRadio width={moderateScale(20)} height={moderateScale(20)} />
|
|
51
|
-
)}
|
|
52
|
-
</View>
|
|
53
|
-
</TouchableOpacity>
|
|
54
|
-
);
|
|
55
|
-
};
|
|
56
19
|
|
|
57
20
|
export const HomeScreen: React.FC<HomeScreenProps> = ({ navigation }) => {
|
|
58
21
|
const user = useAuthStore((state) => state.user);
|
|
59
22
|
const [isLoading, setIsLoading] = useState(false);
|
|
60
23
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
|
61
|
-
const [membersModal, setMembersModal] = useState<boolean>(false);
|
|
62
|
-
const [selectedMember, setSelectedMember] = useState<any>(null);
|
|
63
|
-
const [members, setMembers] = useState<any[]>([]);
|
|
64
|
-
const translateY = useRef(new Animated.Value(0)).current;
|
|
65
|
-
const screenHeight = Dimensions.get('window').height;
|
|
66
|
-
const bottomSheetHeight = screenHeight * 0.45; // 45% of screen height
|
|
67
24
|
const PAGE_SIZE = 10;
|
|
68
25
|
const queryClient = useQueryClient();
|
|
69
|
-
const [selectedClub, setSelectedClub] = useState<any>(null);
|
|
70
26
|
const logout = useAuthStore((state) => state.logout);
|
|
71
|
-
const [joinClubMemberImageUrls, setJoinClubMemberImageUrls] = useState<Record<number, string>>({});
|
|
72
27
|
const [listError, setListError] = useState<string | null>(null);
|
|
73
28
|
|
|
74
29
|
|
|
@@ -250,104 +205,11 @@ export const HomeScreen: React.FC<HomeScreenProps> = ({ navigation }) => {
|
|
|
250
205
|
};
|
|
251
206
|
|
|
252
207
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const handleMemberSelection = (member: any) => {
|
|
256
|
-
setSelectedMember(member);
|
|
257
|
-
console.log('Selected member:', member);
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
// Bottom sheet animation functions
|
|
261
|
-
const showBottomSheet = () => {
|
|
262
|
-
setMembersModal(true);
|
|
263
|
-
Animated.spring(translateY, {
|
|
264
|
-
toValue: 0,
|
|
265
|
-
useNativeDriver: true,
|
|
266
|
-
tension: 100,
|
|
267
|
-
friction: 8,
|
|
268
|
-
}).start();
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
const hideBottomSheet = () => {
|
|
272
|
-
Animated.timing(translateY, {
|
|
273
|
-
toValue: bottomSheetHeight,
|
|
274
|
-
duration: 300,
|
|
275
|
-
useNativeDriver: true,
|
|
276
|
-
}).start(() => {
|
|
277
|
-
setMembersModal(false);
|
|
278
|
-
translateY.setValue(bottomSheetHeight);
|
|
279
|
-
});
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
// PanResponder for swipe gestures
|
|
283
|
-
const panResponder = useRef(
|
|
284
|
-
PanResponder.create({
|
|
285
|
-
onMoveShouldSetPanResponder: (_, gestureState) => {
|
|
286
|
-
return Math.abs(gestureState.dy) > 5;
|
|
287
|
-
},
|
|
288
|
-
onPanResponderGrant: () => {
|
|
289
|
-
translateY.setOffset((translateY as any)._value);
|
|
290
|
-
translateY.setValue(0);
|
|
291
|
-
},
|
|
292
|
-
onPanResponderMove: (_, gestureState) => {
|
|
293
|
-
// Only allow downward movement
|
|
294
|
-
if (gestureState.dy > 0) {
|
|
295
|
-
translateY.setValue(gestureState.dy);
|
|
296
|
-
}
|
|
297
|
-
},
|
|
298
|
-
onPanResponderRelease: (_, gestureState) => {
|
|
299
|
-
translateY.flattenOffset();
|
|
300
|
-
|
|
301
|
-
// If swiped down more than 100px or with high velocity, close the modal
|
|
302
|
-
if (gestureState.dy > 100 || gestureState.vy > 0.5) {
|
|
303
|
-
hideBottomSheet();
|
|
304
|
-
} else {
|
|
305
|
-
// Snap back to original position
|
|
306
|
-
Animated.spring(translateY, {
|
|
307
|
-
toValue: 0,
|
|
308
|
-
useNativeDriver: true,
|
|
309
|
-
tension: 100,
|
|
310
|
-
friction: 8,
|
|
311
|
-
}).start();
|
|
312
|
-
}
|
|
313
|
-
},
|
|
314
|
-
})
|
|
315
|
-
).current;
|
|
316
|
-
|
|
317
|
-
const renderMemberListItem = ({ item }: { item: any }) => (
|
|
318
|
-
<MemberListItem
|
|
319
|
-
item={item}
|
|
320
|
-
isSelected={selectedMember?.id === item?.id}
|
|
321
|
-
onSelect={handleMemberSelection}
|
|
322
|
-
/>
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
|
|
326
208
|
const renderClubItem = ({ item }: any) => {
|
|
327
209
|
return (
|
|
328
210
|
<ClubCard
|
|
329
211
|
club={item}
|
|
330
212
|
onPress={async () => {
|
|
331
|
-
const response = await mainService.getClubMembers({ clubId: item?.id });
|
|
332
|
-
const members = response.data.data;
|
|
333
|
-
const sortedMembers = members.sort((a: any, b: any) => {
|
|
334
|
-
if (a?.isOwner) return -1;
|
|
335
|
-
if (b?.isOwner) return 1;
|
|
336
|
-
return 0;
|
|
337
|
-
});
|
|
338
|
-
setSelectedClub(item);
|
|
339
|
-
setMembers(sortedMembers.map((member: any) => ({
|
|
340
|
-
...member,
|
|
341
|
-
profileImageUrl: joinClubMemberImageUrls[member?.id] || undefined
|
|
342
|
-
})));
|
|
343
|
-
|
|
344
|
-
if (sortedMembers.length === 1) {
|
|
345
|
-
setSelectedMember(sortedMembers[0]);
|
|
346
|
-
navigation.navigate('ClubDetails', { ...item, selectedMember: sortedMembers[0] });
|
|
347
|
-
} else {
|
|
348
|
-
setSelectedMember(null);
|
|
349
|
-
showBottomSheet();
|
|
350
|
-
}
|
|
351
213
|
}}
|
|
352
214
|
/>
|
|
353
215
|
);
|
|
@@ -428,80 +290,6 @@ export const HomeScreen: React.FC<HomeScreenProps> = ({ navigation }) => {
|
|
|
428
290
|
/>
|
|
429
291
|
</View>
|
|
430
292
|
|
|
431
|
-
|
|
432
|
-
<Modal
|
|
433
|
-
visible={membersModal}
|
|
434
|
-
animationType="fade"
|
|
435
|
-
transparent={true}
|
|
436
|
-
onRequestClose={hideBottomSheet}
|
|
437
|
-
>
|
|
438
|
-
<View style={styles.modalOverlay}>
|
|
439
|
-
<TouchableOpacity
|
|
440
|
-
style={styles.modalBackdrop}
|
|
441
|
-
activeOpacity={1}
|
|
442
|
-
onPress={hideBottomSheet}
|
|
443
|
-
/>
|
|
444
|
-
<Animated.View
|
|
445
|
-
style={[
|
|
446
|
-
styles.modalContainer,
|
|
447
|
-
{
|
|
448
|
-
transform: [{ translateY }],
|
|
449
|
-
},
|
|
450
|
-
]}
|
|
451
|
-
|
|
452
|
-
>
|
|
453
|
-
<View style={styles.dragHandle} {...panResponder.panHandlers} />
|
|
454
|
-
<FlatList
|
|
455
|
-
data={members}
|
|
456
|
-
renderItem={renderMemberListItem}
|
|
457
|
-
style={styles.membersList}
|
|
458
|
-
showsVerticalScrollIndicator={false}
|
|
459
|
-
ListHeaderComponent={() => {
|
|
460
|
-
return (
|
|
461
|
-
<View>
|
|
462
|
-
<View style={styles.headerContainer}>
|
|
463
|
-
<Text style={styles.mamberHeaderTitle}>Continue as</Text>
|
|
464
|
-
</View>
|
|
465
|
-
</View>
|
|
466
|
-
)
|
|
467
|
-
}}
|
|
468
|
-
|
|
469
|
-
keyExtractor={(item, index) => {
|
|
470
|
-
// Create a more robust key for members
|
|
471
|
-
const id = item?.id?.toString() || '';
|
|
472
|
-
const name = item?.name || '';
|
|
473
|
-
const email = item?.email || '';
|
|
474
|
-
const memberCode = item?.membershipCode || '';
|
|
475
|
-
const createdAt = item?.createdAt || '';
|
|
476
|
-
// Create a unique composite key using multiple attributes
|
|
477
|
-
const keyParts = [id, name, email, memberCode, createdAt].filter(part => part && part.toString().trim() !== '');
|
|
478
|
-
|
|
479
|
-
if (keyParts.length > 0) {
|
|
480
|
-
return `member-${keyParts.join('-')}`;
|
|
481
|
-
}
|
|
482
|
-
// Ultimate fallback with index to ensure uniqueness
|
|
483
|
-
return `member-unknown-${index}`;
|
|
484
|
-
}}
|
|
485
|
-
|
|
486
|
-
/>
|
|
487
|
-
|
|
488
|
-
<Button
|
|
489
|
-
title="Continue"
|
|
490
|
-
onPress={() => {
|
|
491
|
-
navigation.navigate('ClubDetails', {
|
|
492
|
-
...selectedClub,
|
|
493
|
-
selectedMember: selectedMember
|
|
494
|
-
});
|
|
495
|
-
hideBottomSheet();
|
|
496
|
-
}}
|
|
497
|
-
variant="primary"
|
|
498
|
-
size="medium"
|
|
499
|
-
style={styles.nextButton}
|
|
500
|
-
disabled={!selectedMember}
|
|
501
|
-
/>
|
|
502
|
-
</Animated.View>
|
|
503
|
-
</View>
|
|
504
|
-
</Modal>
|
|
505
293
|
</View>
|
|
506
294
|
);
|
|
507
295
|
};
|
|
@@ -7,21 +7,21 @@ import {
|
|
|
7
7
|
StatusBar,
|
|
8
8
|
Platform,
|
|
9
9
|
} from 'react-native';
|
|
10
|
-
import { Button, TextInput } from '
|
|
11
|
-
import { theme } from '
|
|
12
|
-
import { Strings } from '
|
|
13
|
-
import { validateEmail, validatePassword } from '
|
|
14
|
-
import SVG from '
|
|
15
|
-
import Images from '
|
|
10
|
+
import { Button, TextInput } from '@components/common';
|
|
11
|
+
import { theme } from '@constants';
|
|
12
|
+
import { Strings } from '@constants/strings';
|
|
13
|
+
import { validateEmail, validatePassword } from '@utils';
|
|
14
|
+
import SVG from '@assets/icons';
|
|
15
|
+
import Images from '@assets/images';
|
|
16
16
|
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
|
|
17
|
-
import { moderateScale, verticalScale } from '
|
|
18
|
-
import { Fonts } from '
|
|
17
|
+
import { moderateScale, verticalScale } from '@utils/scaling';
|
|
18
|
+
import { Fonts } from '@constants/Fonts';
|
|
19
19
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
20
|
-
import { hideLoader, showLoader } from '
|
|
21
|
-
import ToastManager from '
|
|
22
|
-
import { useLogin, getApiErrorInfo } from '
|
|
23
|
-
import { useAuthStore } from '
|
|
24
|
-
import NotificationManager from '
|
|
20
|
+
import { hideLoader, showLoader } from '@components/common/AppLoader';
|
|
21
|
+
import ToastManager from '@components/common/ToastManager';
|
|
22
|
+
import { useLogin, getApiErrorInfo } from '@services/authService';
|
|
23
|
+
import { useAuthStore } from '@stores/authStore';
|
|
24
|
+
import NotificationManager from '@utils/NotificationManager';
|
|
25
25
|
|
|
26
26
|
interface LoginScreenProps {
|
|
27
27
|
navigation: any;
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
export * from './LoginScreen';
|
|
2
|
-
export * from './RegisterScreen';
|
|
3
|
-
export * from './ForgotPasswordScreen';
|
|
4
|
-
export * from './OTPVerifyScreen';
|
|
5
|
-
export * from './AddMamber';
|
|
6
1
|
export * from './WalcomeScreen';
|
|
7
|
-
export * from './
|
|
2
|
+
export * from './LoginScreen';
|
|
8
3
|
|
|
@@ -1,40 +1,5 @@
|
|
|
1
1
|
export * from './HomeScreen';
|
|
2
|
-
export * from './ProfileScreen';
|
|
3
|
-
export * from './SettingsScreen';
|
|
4
|
-
export * from './DetailsScreen';
|
|
5
|
-
export * from './SportHubScreen';
|
|
6
|
-
export * from './auth';
|
|
7
|
-
//Club Screens
|
|
8
|
-
export * from './clubs/JoinClub';
|
|
9
|
-
export * from './clubs/ClubDeteils';
|
|
10
|
-
export * from './clubs/Announcements';
|
|
11
|
-
export * from './raffles/RafflesScreen';
|
|
12
2
|
|
|
13
|
-
//Team Screens
|
|
14
|
-
export * from './teams/MyTeamScreen';
|
|
15
|
-
export * from './teams/MyTeamDetailsScreen';
|
|
16
|
-
export * from './teams/JoinTeamScreen';
|
|
17
|
-
export * from './teams/PendingRequestsScreen';
|
|
18
|
-
|
|
19
|
-
//Chat Screens
|
|
20
|
-
export * from './chat/ChatThreadsScreen';
|
|
21
|
-
export * from './chat/ChatScreen';
|
|
22
|
-
export * from './chat/ReportMessageScreen';
|
|
23
|
-
export * from './volunteerOpportunities/VolunteerOpportunitiesScreen';
|
|
24
|
-
export * from './volunteerOpportunities/VolunteerOpportunitiesDetailsScreen';
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
//Raffles Screens
|
|
28
|
-
export * from './raffles/MyReferralMembersScreen';
|
|
29
|
-
export * from './raffles/RaffleDetailsScreen';
|
|
30
|
-
export * from './clubs/BuyRaffleTicketsScreen';
|
|
31
|
-
|
|
32
|
-
// Reminder Screen
|
|
33
|
-
export * from './volunteerOpportunities/SetReminderScreen';
|
|
34
|
-
export * from './raffles/SetRaffleReminderScreen';
|
|
35
|
-
|
|
36
|
-
// Event Screen
|
|
37
|
-
export * from './events/EventScreen';
|
|
38
3
|
|
|
39
4
|
|
|
40
5
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import { MMKV } from 'react-native-mmkv';
|
|
3
|
-
import { StorageService } from '
|
|
3
|
+
import { StorageService } from '@utils/storage';
|
|
4
4
|
import { Platform } from 'react-native';
|
|
5
|
-
import ToastManager from '
|
|
6
|
-
import { useAuthStore } from '
|
|
5
|
+
import ToastManager from '@components/common/ToastManager';
|
|
6
|
+
import { useAuthStore } from '@stores/authStore';
|
|
7
7
|
|
|
8
8
|
// API Configuration
|
|
9
|
-
export const API_BASE_URL =
|
|
10
|
-
export const CHAT_HUB_URL =
|
|
9
|
+
export const API_BASE_URL = "https://clubyakkadev.24livehost.com/api/v1/"; // prod api url
|
|
10
|
+
export const CHAT_HUB_URL = "https://clubyakkadev.24livehost.com/chathub"; // dev chat hub url
|
|
11
11
|
|
|
12
12
|
// Create axios instance with default config
|
|
13
13
|
const offsetTime = new Date().getTimezoneOffset() * 60 * -1;
|