create-gufran-expo-app 2.0.3 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- 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
|
@@ -1,758 +0,0 @@
|
|
|
1
|
-
import React, { useMemo, useCallback, useState, useRef } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
View,
|
|
4
|
-
Text,
|
|
5
|
-
StyleSheet,
|
|
6
|
-
StatusBar,
|
|
7
|
-
Platform,
|
|
8
|
-
TouchableOpacity,
|
|
9
|
-
Image,
|
|
10
|
-
FlatList,
|
|
11
|
-
ListRenderItem,
|
|
12
|
-
Share,
|
|
13
|
-
ActivityIndicator,
|
|
14
|
-
RefreshControl,
|
|
15
|
-
Modal,
|
|
16
|
-
Animated,
|
|
17
|
-
Dimensions,
|
|
18
|
-
PanResponder,
|
|
19
|
-
} from 'react-native';
|
|
20
|
-
import { MyReferralMembersScreenProps } from '@navigation';
|
|
21
|
-
import { theme } from '@constants';
|
|
22
|
-
import { moderateScale } from '@utils/scaling';
|
|
23
|
-
import { Fonts } from '@constants/Fonts';
|
|
24
|
-
import SVG from '@assets/icons';
|
|
25
|
-
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
26
|
-
import { Button } from '@components/common';
|
|
27
|
-
import { useInfiniteReferrerMemberSales, ReferrerMember, mainService } from '@services/mainServices';
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
export const MyReferralMembersScreen: React.FC<MyReferralMembersScreenProps> = ({ navigation, route }) => {
|
|
31
|
-
const { selectedClub, selectedMember: initialSelectedMember, raffleId, raffleTitle } = route?.params ?? {};
|
|
32
|
-
|
|
33
|
-
const memberId = initialSelectedMember?.id;
|
|
34
|
-
const pageSize = 10;
|
|
35
|
-
|
|
36
|
-
// Fetch referral members with pagination
|
|
37
|
-
const {
|
|
38
|
-
data,
|
|
39
|
-
isLoading,
|
|
40
|
-
isError,
|
|
41
|
-
error,
|
|
42
|
-
fetchNextPage,
|
|
43
|
-
hasNextPage,
|
|
44
|
-
isFetchingNextPage,
|
|
45
|
-
refetch,
|
|
46
|
-
isRefetching,
|
|
47
|
-
} = useInfiniteReferrerMemberSales(raffleId, memberId, pageSize);
|
|
48
|
-
|
|
49
|
-
// Modal state
|
|
50
|
-
const [ticketModalVisible, setTicketModalVisible] = useState(false);
|
|
51
|
-
const [ticketDetailsLoading, setTicketDetailsLoading] = useState(false);
|
|
52
|
-
const [ticketNumbers, setTicketNumbers] = useState<any>([]);
|
|
53
|
-
const translateY = useRef(new Animated.Value(0)).current;
|
|
54
|
-
const screenHeight = Dimensions.get('window').height;
|
|
55
|
-
const bottomSheetHeight = screenHeight * 0.5; // 50% of screen height
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// Flatten paginated data
|
|
59
|
-
const referralMembers = useMemo(() => {
|
|
60
|
-
if (!data?.pages) return [];
|
|
61
|
-
|
|
62
|
-
return data.pages.flatMap((page) => {
|
|
63
|
-
// Access the correct nested structure: data.data.data.salesList
|
|
64
|
-
const responseData = page?.data?.data;
|
|
65
|
-
|
|
66
|
-
if (responseData && typeof responseData === 'object') {
|
|
67
|
-
// Check for nested data.data.salesList structure
|
|
68
|
-
if ('data' in responseData && responseData.data && typeof responseData.data === 'object') {
|
|
69
|
-
const nestedData = responseData.data as any;
|
|
70
|
-
if ('salesList' in nestedData && Array.isArray(nestedData.salesList)) {
|
|
71
|
-
return nestedData.salesList;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
// Direct salesList
|
|
75
|
-
if ('salesList' in responseData && Array.isArray(responseData.salesList)) {
|
|
76
|
-
return responseData.salesList;
|
|
77
|
-
}
|
|
78
|
-
// Fallback to other possible structures
|
|
79
|
-
if ('members' in responseData && Array.isArray(responseData.members)) {
|
|
80
|
-
return responseData.members;
|
|
81
|
-
} else if ('referralMembers' in responseData && Array.isArray(responseData.referralMembers)) {
|
|
82
|
-
return responseData.referralMembers;
|
|
83
|
-
} else if (Array.isArray(responseData)) {
|
|
84
|
-
return responseData;
|
|
85
|
-
}
|
|
86
|
-
} else if (Array.isArray(page?.data?.data)) {
|
|
87
|
-
return page.data.data;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return [];
|
|
91
|
-
});
|
|
92
|
-
}, [data]);
|
|
93
|
-
|
|
94
|
-
// Calculate total sales from API response
|
|
95
|
-
const totalSales = useMemo(() => {
|
|
96
|
-
if (!data?.pages?.[0]) return 0;
|
|
97
|
-
|
|
98
|
-
const firstPage = data.pages[0];
|
|
99
|
-
const responseData = firstPage?.data?.data;
|
|
100
|
-
|
|
101
|
-
// Try to get totalPurchasedTicketCount from nested data structure
|
|
102
|
-
if (responseData && typeof responseData === 'object') {
|
|
103
|
-
if ('data' in responseData && responseData.data && typeof responseData.data === 'object') {
|
|
104
|
-
const nestedData = responseData.data as any;
|
|
105
|
-
if (typeof nestedData.totalPurchasedTicketCount === 'number') {
|
|
106
|
-
return nestedData.totalPurchasedTicketCount;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
// Try direct totalPurchasedTicketCount
|
|
110
|
-
if ('totalPurchasedTicketCount' in responseData && typeof responseData.totalPurchasedTicketCount === 'number') {
|
|
111
|
-
return responseData.totalPurchasedTicketCount;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Fallback: calculate from member data
|
|
116
|
-
return referralMembers.reduce((sum, member) => {
|
|
117
|
-
const tickets = member.purchasedTicketCount ?? member.ticketCount ?? member.ticketsSold ?? member.totalTickets ?? 0;
|
|
118
|
-
return sum + tickets;
|
|
119
|
-
}, 0);
|
|
120
|
-
}, [data, referralMembers]);
|
|
121
|
-
|
|
122
|
-
const handleReferToFriends = async () => {
|
|
123
|
-
try {
|
|
124
|
-
const response = await mainService.getReferralCode({
|
|
125
|
-
raffleId: raffleId || 0,
|
|
126
|
-
memberId: memberId || 0,
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
const responseData = response?.data?.data;
|
|
130
|
-
const referralCode = responseData?.referralCode || '';
|
|
131
|
-
const clubCode = responseData?.clubCode || '';
|
|
132
|
-
const clubName = responseData?.clubName || 'ClubYakka';
|
|
133
|
-
|
|
134
|
-
const appLink = '(App Link)';
|
|
135
|
-
const shareMessage =
|
|
136
|
-
`Join the *${raffleTitle}* raffle on ClubYakka app!
|
|
137
|
-
|
|
138
|
-
Use my referral code: *${referralCode}* when buying tickets
|
|
139
|
-
|
|
140
|
-
Steps to buy:
|
|
141
|
-
1. Ensure you have ${clubName} club already joined or if not, find it with club code: #${clubCode} to join it
|
|
142
|
-
2. Continue as desired member in Club Dashboard
|
|
143
|
-
3. Click Raffle section and find raffle: *${raffleTitle}*
|
|
144
|
-
4. When buying raffle tickets, apply my code: *${referralCode}*
|
|
145
|
-
5. Purchase raffle tickets and WIN!
|
|
146
|
-
|
|
147
|
-
Click the link to open the app ${appLink}`;
|
|
148
|
-
|
|
149
|
-
Share.share({
|
|
150
|
-
message: shareMessage,
|
|
151
|
-
title: `${clubName} Raffle on ClubYakka`
|
|
152
|
-
});
|
|
153
|
-
} catch (error) {
|
|
154
|
-
console.error('Failed to get referral code:', error);
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
// Handle load more for pagination
|
|
159
|
-
const handleLoadMore = useCallback(() => {
|
|
160
|
-
if (hasNextPage && !isFetchingNextPage) {
|
|
161
|
-
fetchNextPage();
|
|
162
|
-
}
|
|
163
|
-
}, [hasNextPage, isFetchingNextPage, fetchNextPage]);
|
|
164
|
-
|
|
165
|
-
// Handle pull to refresh
|
|
166
|
-
const handleRefresh = useCallback(() => {
|
|
167
|
-
refetch();
|
|
168
|
-
}, [refetch]);
|
|
169
|
-
|
|
170
|
-
// Bottom sheet animation functions
|
|
171
|
-
const showBottomSheet = () => {
|
|
172
|
-
setTicketModalVisible(true);
|
|
173
|
-
Animated.spring(translateY, {
|
|
174
|
-
toValue: 0,
|
|
175
|
-
useNativeDriver: true,
|
|
176
|
-
tension: 100,
|
|
177
|
-
friction: 8,
|
|
178
|
-
}).start();
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
const hideBottomSheet = () => {
|
|
182
|
-
Animated.timing(translateY, {
|
|
183
|
-
toValue: bottomSheetHeight,
|
|
184
|
-
duration: 300,
|
|
185
|
-
useNativeDriver: true,
|
|
186
|
-
}).start(() => {
|
|
187
|
-
setTicketModalVisible(false);
|
|
188
|
-
translateY.setValue(bottomSheetHeight);
|
|
189
|
-
setTicketNumbers([]);
|
|
190
|
-
});
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
// PanResponder for swipe gestures
|
|
194
|
-
const panResponder = useRef(
|
|
195
|
-
PanResponder.create({
|
|
196
|
-
onMoveShouldSetPanResponder: (_, gestureState) => {
|
|
197
|
-
return Math.abs(gestureState.dy) > 5;
|
|
198
|
-
},
|
|
199
|
-
onPanResponderGrant: () => {
|
|
200
|
-
translateY.setOffset((translateY as any)._value);
|
|
201
|
-
translateY.setValue(0);
|
|
202
|
-
},
|
|
203
|
-
onPanResponderMove: (_, gestureState) => {
|
|
204
|
-
// Only allow downward movement
|
|
205
|
-
if (gestureState.dy > 0) {
|
|
206
|
-
translateY.setValue(gestureState.dy);
|
|
207
|
-
}
|
|
208
|
-
},
|
|
209
|
-
onPanResponderRelease: (_, gestureState) => {
|
|
210
|
-
translateY.flattenOffset();
|
|
211
|
-
|
|
212
|
-
// If swiped down more than 100px or with high velocity, close the modal
|
|
213
|
-
if (gestureState.dy > 100 || gestureState.vy > 0.5) {
|
|
214
|
-
hideBottomSheet();
|
|
215
|
-
} else {
|
|
216
|
-
// Snap back to original position
|
|
217
|
-
Animated.spring(translateY, {
|
|
218
|
-
toValue: 0,
|
|
219
|
-
useNativeDriver: true,
|
|
220
|
-
tension: 100,
|
|
221
|
-
friction: 8,
|
|
222
|
-
}).start();
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
})
|
|
226
|
-
).current;
|
|
227
|
-
|
|
228
|
-
// Handle ticket badge press
|
|
229
|
-
const handleTicketPress = async (member: ReferrerMember) => {
|
|
230
|
-
try {
|
|
231
|
-
setTicketDetailsLoading(true);
|
|
232
|
-
|
|
233
|
-
const response = await mainService.getTicketDetails({
|
|
234
|
-
raffleId: raffleId || 0,
|
|
235
|
-
memberId: member?.memberId || 0,
|
|
236
|
-
purchasedMemberId: member.memberId || member.id || 0,
|
|
237
|
-
});
|
|
238
|
-
console.log("data===>>>", JSON.stringify(response));
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if (response?.data?.data) {
|
|
242
|
-
setTicketNumbers(response?.data?.data || []);
|
|
243
|
-
showBottomSheet();
|
|
244
|
-
}
|
|
245
|
-
} catch (error) {
|
|
246
|
-
console.error('Failed to fetch ticket details:', error);
|
|
247
|
-
} finally {
|
|
248
|
-
setTicketDetailsLoading(false);
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
// Render individual member item
|
|
254
|
-
const renderMemberItem: ListRenderItem<ReferrerMember> = ({ item }) => {
|
|
255
|
-
const displayName = item.memberName || item.name || 'Unknown';
|
|
256
|
-
const profileImg = item.profileImage || item.profileImageUrl;
|
|
257
|
-
const tickets = item.purchasedTicketCount ?? item.ticketCount ?? item.ticketsSold ?? item.totalTickets ?? 0;
|
|
258
|
-
|
|
259
|
-
return (
|
|
260
|
-
<View style={styles.memberRow}>
|
|
261
|
-
<View style={styles.memberInfo}>
|
|
262
|
-
<View style={styles.memberAvatar}>
|
|
263
|
-
{profileImg ? (
|
|
264
|
-
<Image source={{ uri: profileImg }} style={styles.avatarImage} resizeMode="cover" />
|
|
265
|
-
) : (
|
|
266
|
-
<View style={styles.avatarPlaceholder}>
|
|
267
|
-
<SVG.UsersIcon width={moderateScale(24)} height={moderateScale(24)} />
|
|
268
|
-
</View>
|
|
269
|
-
)}
|
|
270
|
-
</View>
|
|
271
|
-
<Text style={styles.memberName}>{displayName}</Text>
|
|
272
|
-
</View>
|
|
273
|
-
<TouchableOpacity
|
|
274
|
-
style={styles.ticketBadge}
|
|
275
|
-
onPress={() => handleTicketPress(item)}
|
|
276
|
-
disabled={ticketDetailsLoading}
|
|
277
|
-
>
|
|
278
|
-
{ticketDetailsLoading ? (
|
|
279
|
-
<ActivityIndicator size="small" color={theme.colors.blue} />
|
|
280
|
-
) : (
|
|
281
|
-
<Text style={styles.ticketCount}>{tickets} Ticket{tickets !== 1 ? 's' : ''}</Text>
|
|
282
|
-
)}
|
|
283
|
-
</TouchableOpacity>
|
|
284
|
-
</View>
|
|
285
|
-
);
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
// Render footer loader
|
|
289
|
-
const renderFooter = () => {
|
|
290
|
-
if (!isFetchingNextPage) return null;
|
|
291
|
-
return (
|
|
292
|
-
<View style={styles.footerLoader}>
|
|
293
|
-
<ActivityIndicator size="small" color={theme.colors.blue} />
|
|
294
|
-
</View>
|
|
295
|
-
);
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
// Render empty state
|
|
299
|
-
const renderEmptyComponent = () => {
|
|
300
|
-
if (isLoading) {
|
|
301
|
-
return (
|
|
302
|
-
<View style={styles.emptyContainer}>
|
|
303
|
-
<ActivityIndicator size="large" color={theme.colors.blue} />
|
|
304
|
-
<Text style={styles.emptyText}>Loading referral members...</Text>
|
|
305
|
-
</View>
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (isError) {
|
|
310
|
-
return (
|
|
311
|
-
<View style={styles.emptyContainer}>
|
|
312
|
-
<Text style={styles.errorText}>Failed to load referral members</Text>
|
|
313
|
-
<Text style={styles.errorSubText}>{error?.message || 'Please try again'}</Text>
|
|
314
|
-
<TouchableOpacity onPress={handleRefresh} style={styles.retryButton}>
|
|
315
|
-
<Text style={styles.retryButtonText}>Retry</Text>
|
|
316
|
-
</TouchableOpacity>
|
|
317
|
-
</View>
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
return (
|
|
322
|
-
<View style={styles.emptyContainer}>
|
|
323
|
-
<Text style={styles.emptyText}>No referral members found</Text>
|
|
324
|
-
<Text style={styles.emptySubText}>Start referring friends to see them here</Text>
|
|
325
|
-
</View>
|
|
326
|
-
);
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
return (
|
|
330
|
-
|
|
331
|
-
console.log("hhhh", ticketNumbers),
|
|
332
|
-
|
|
333
|
-
<View style={styles.container}>
|
|
334
|
-
<StatusBar
|
|
335
|
-
barStyle="light-content"
|
|
336
|
-
backgroundColor={theme.colors.blue}
|
|
337
|
-
translucent={Platform.OS === 'android' ? true : false}
|
|
338
|
-
/>
|
|
339
|
-
{Platform.OS === 'ios' && <View style={styles.statusBarBackground} />}
|
|
340
|
-
<SafeAreaView style={styles.header}>
|
|
341
|
-
<View style={styles.headerTopRow}>
|
|
342
|
-
<TouchableOpacity onPress={() => navigation.goBack()}>
|
|
343
|
-
<SVG.arrowLeft_white width={moderateScale(25)} height={moderateScale(25)} />
|
|
344
|
-
</TouchableOpacity>
|
|
345
|
-
<View style={styles.clubInfoWrapper}>
|
|
346
|
-
<View style={styles.userConSty}>
|
|
347
|
-
{!!selectedClub?.clubImage ? (
|
|
348
|
-
<Image source={{ uri: selectedClub?.clubImage }} style={styles.userDetailsSty} resizeMode="cover" />
|
|
349
|
-
) : (
|
|
350
|
-
<View style={styles.placeholderLogoHeader}>
|
|
351
|
-
<SVG.UsersIcon width={moderateScale(20)} height={moderateScale(20)} />
|
|
352
|
-
</View>
|
|
353
|
-
)}
|
|
354
|
-
</View>
|
|
355
|
-
<Text style={styles.userNameSty}>{selectedClub?.clubName || 'Unknown Club'}</Text>
|
|
356
|
-
</View>
|
|
357
|
-
</View>
|
|
358
|
-
<View style={styles.titleWrapper}>
|
|
359
|
-
<Text style={styles.headerTitle}>My Referral Members Sales</Text>
|
|
360
|
-
</View>
|
|
361
|
-
<View style={styles.addMemberContainer} />
|
|
362
|
-
<View style={styles.content}>
|
|
363
|
-
<View style={{ paddingHorizontal: theme.spacing.lg }}>
|
|
364
|
-
|
|
365
|
-
<View style={styles.headerCard}>
|
|
366
|
-
<Text style={styles.totalSalesLabel}>Total Sales</Text>
|
|
367
|
-
<View style={styles.totalSalesBadge}>
|
|
368
|
-
<Text style={styles.totalSalesCount}>{totalSales}</Text>
|
|
369
|
-
</View>
|
|
370
|
-
</View>
|
|
371
|
-
<View style={{ height: moderateScale(500) }}>
|
|
372
|
-
<FlatList
|
|
373
|
-
data={referralMembers}
|
|
374
|
-
keyExtractor={(item, index) => item.id?.toString() || item.memberId?.toString() || index.toString()}
|
|
375
|
-
renderItem={renderMemberItem}
|
|
376
|
-
contentContainerStyle={styles.listContent}
|
|
377
|
-
showsVerticalScrollIndicator={false}
|
|
378
|
-
onEndReached={handleLoadMore}
|
|
379
|
-
onEndReachedThreshold={0.3}
|
|
380
|
-
ListFooterComponent={renderFooter}
|
|
381
|
-
ListEmptyComponent={renderEmptyComponent}
|
|
382
|
-
refreshControl={
|
|
383
|
-
<RefreshControl
|
|
384
|
-
refreshing={isRefetching}
|
|
385
|
-
onRefresh={handleRefresh}
|
|
386
|
-
tintColor={theme.colors.blue}
|
|
387
|
-
colors={[theme.colors.blue]}
|
|
388
|
-
/>
|
|
389
|
-
}
|
|
390
|
-
/>
|
|
391
|
-
</View>
|
|
392
|
-
<Button
|
|
393
|
-
title="Refer to More Friends"
|
|
394
|
-
onPress={handleReferToFriends}
|
|
395
|
-
variant="outline"
|
|
396
|
-
textStyle={styles.referButtonText}
|
|
397
|
-
style={styles.referButton}
|
|
398
|
-
size="medium"
|
|
399
|
-
/>
|
|
400
|
-
</View>
|
|
401
|
-
</View>
|
|
402
|
-
</SafeAreaView>
|
|
403
|
-
|
|
404
|
-
{/* Ticket Details Modal */}
|
|
405
|
-
<Modal
|
|
406
|
-
visible={ticketModalVisible}
|
|
407
|
-
animationType="fade"
|
|
408
|
-
transparent={true}
|
|
409
|
-
onRequestClose={hideBottomSheet}
|
|
410
|
-
>
|
|
411
|
-
<View style={styles.modalOverlay}>
|
|
412
|
-
<TouchableOpacity
|
|
413
|
-
style={styles.modalBackdrop}
|
|
414
|
-
activeOpacity={1}
|
|
415
|
-
onPress={hideBottomSheet}
|
|
416
|
-
/>
|
|
417
|
-
<Animated.View
|
|
418
|
-
style={[
|
|
419
|
-
styles.modalContainer,
|
|
420
|
-
{
|
|
421
|
-
transform: [{ translateY }],
|
|
422
|
-
},
|
|
423
|
-
]}
|
|
424
|
-
>
|
|
425
|
-
<View style={styles.dragHandle} {...panResponder.panHandlers} />
|
|
426
|
-
<View style={styles.modalHeader}>
|
|
427
|
-
<Text style={styles.modalTitle}>Ticket Details</Text>
|
|
428
|
-
</View>
|
|
429
|
-
<FlatList
|
|
430
|
-
data={ticketNumbers}
|
|
431
|
-
keyExtractor={(item, index) => `ticket-${item}-${index}`}
|
|
432
|
-
contentContainerStyle={styles.ticketListContent}
|
|
433
|
-
showsVerticalScrollIndicator={false}
|
|
434
|
-
renderItem={({ item }) => (
|
|
435
|
-
<View style={styles.ticketNumberBadge}>
|
|
436
|
-
<Text style={styles.ticketNumberText}>{item?.ticketNumber}</Text>
|
|
437
|
-
</View>
|
|
438
|
-
)}
|
|
439
|
-
ListEmptyComponent={() => (
|
|
440
|
-
<View style={styles.emptyTicketContainer}>
|
|
441
|
-
<Text style={styles.emptyTicketText}>No tickets found</Text>
|
|
442
|
-
</View>
|
|
443
|
-
)}
|
|
444
|
-
/>
|
|
445
|
-
</Animated.View>
|
|
446
|
-
</View>
|
|
447
|
-
</Modal>
|
|
448
|
-
</View>
|
|
449
|
-
);
|
|
450
|
-
};
|
|
451
|
-
|
|
452
|
-
const styles = StyleSheet.create({
|
|
453
|
-
container: {
|
|
454
|
-
flex: 1,
|
|
455
|
-
backgroundColor: theme.colors.blue,
|
|
456
|
-
},
|
|
457
|
-
statusBarBackground: {
|
|
458
|
-
position: 'absolute',
|
|
459
|
-
top: 0,
|
|
460
|
-
left: 0,
|
|
461
|
-
right: 0,
|
|
462
|
-
height: Platform.OS === 'ios' ? 44 : 0,
|
|
463
|
-
backgroundColor: theme.colors.blue,
|
|
464
|
-
zIndex: 1000,
|
|
465
|
-
},
|
|
466
|
-
header: {
|
|
467
|
-
flex: 1,
|
|
468
|
-
backgroundColor: theme.colors.blue,
|
|
469
|
-
},
|
|
470
|
-
userConSty: {
|
|
471
|
-
marginHorizontal: moderateScale(10),
|
|
472
|
-
width: moderateScale(30),
|
|
473
|
-
height: moderateScale(30),
|
|
474
|
-
borderRadius: moderateScale(15),
|
|
475
|
-
borderWidth: 1.5,
|
|
476
|
-
borderColor: theme.colors.imageBorder,
|
|
477
|
-
backgroundColor: theme.colors.background,
|
|
478
|
-
alignItems: 'center',
|
|
479
|
-
justifyContent: 'center',
|
|
480
|
-
},
|
|
481
|
-
headerTopRow: {
|
|
482
|
-
flexDirection: 'row',
|
|
483
|
-
alignItems: 'center',
|
|
484
|
-
paddingHorizontal: theme.spacing.lg,
|
|
485
|
-
},
|
|
486
|
-
clubInfoWrapper: {
|
|
487
|
-
flexDirection: 'row',
|
|
488
|
-
alignItems: 'center',
|
|
489
|
-
},
|
|
490
|
-
headerTitle: {
|
|
491
|
-
marginTop: moderateScale(10),
|
|
492
|
-
fontFamily: Fonts.outfitMedium,
|
|
493
|
-
fontSize: moderateScale(22),
|
|
494
|
-
color: theme.colors.white,
|
|
495
|
-
},
|
|
496
|
-
titleWrapper: {
|
|
497
|
-
paddingHorizontal: theme.spacing.lg,
|
|
498
|
-
},
|
|
499
|
-
content: {
|
|
500
|
-
flex: 1,
|
|
501
|
-
backgroundColor: theme.colors.background,
|
|
502
|
-
paddingTop: theme.spacing.md,
|
|
503
|
-
borderTopLeftRadius: moderateScale(30),
|
|
504
|
-
borderTopRightRadius: moderateScale(30),
|
|
505
|
-
},
|
|
506
|
-
userDetailsSty: {
|
|
507
|
-
width: moderateScale(30),
|
|
508
|
-
height: moderateScale(30),
|
|
509
|
-
borderRadius: moderateScale(15),
|
|
510
|
-
},
|
|
511
|
-
placeholderLogoHeader: {
|
|
512
|
-
width: moderateScale(20),
|
|
513
|
-
height: moderateScale(20),
|
|
514
|
-
borderRadius: moderateScale(10),
|
|
515
|
-
alignItems: 'center',
|
|
516
|
-
justifyContent: 'center',
|
|
517
|
-
},
|
|
518
|
-
userNameSty: {
|
|
519
|
-
marginTop: moderateScale(5),
|
|
520
|
-
color: theme.colors.white,
|
|
521
|
-
fontFamily: Fonts.outfitMedium,
|
|
522
|
-
fontSize: moderateScale(15),
|
|
523
|
-
},
|
|
524
|
-
addMemberContainer: {
|
|
525
|
-
backgroundColor: theme.colors.blue,
|
|
526
|
-
paddingHorizontal: theme.spacing.lg,
|
|
527
|
-
paddingBottom: theme.spacing.md,
|
|
528
|
-
},
|
|
529
|
-
listContent: {
|
|
530
|
-
paddingTop: theme.spacing.md,
|
|
531
|
-
paddingBottom: theme.spacing.xl,
|
|
532
|
-
},
|
|
533
|
-
// Header card with total sales
|
|
534
|
-
headerCard: {
|
|
535
|
-
backgroundColor: theme.colors.lightLavenderGray,
|
|
536
|
-
borderRadius: theme.borderRadius.lg,
|
|
537
|
-
paddingHorizontal: theme.spacing.lg,
|
|
538
|
-
paddingVertical: theme.spacing.sm,
|
|
539
|
-
flexDirection: 'row',
|
|
540
|
-
justifyContent: 'space-between',
|
|
541
|
-
alignItems: 'center',
|
|
542
|
-
marginBottom: theme.spacing.xs
|
|
543
|
-
},
|
|
544
|
-
totalSalesLabel: {
|
|
545
|
-
fontFamily: Fonts.outfitMedium,
|
|
546
|
-
fontSize: theme.typography.fontSize.md,
|
|
547
|
-
color: theme.colors.blue,
|
|
548
|
-
},
|
|
549
|
-
totalSalesBadge: {
|
|
550
|
-
width: moderateScale(25),
|
|
551
|
-
height: moderateScale(25),
|
|
552
|
-
borderRadius: moderateScale(12.5),
|
|
553
|
-
backgroundColor: theme.colors.appleGreen,
|
|
554
|
-
alignItems: 'center',
|
|
555
|
-
justifyContent: 'center',
|
|
556
|
-
},
|
|
557
|
-
totalSalesCount: {
|
|
558
|
-
fontFamily: Fonts.outfitMedium,
|
|
559
|
-
fontSize: theme.typography.fontSize.xs,
|
|
560
|
-
color: theme.colors.blue,
|
|
561
|
-
},
|
|
562
|
-
// Member row
|
|
563
|
-
memberRow: {
|
|
564
|
-
flexDirection: 'row',
|
|
565
|
-
alignItems: 'center',
|
|
566
|
-
justifyContent: 'space-between',
|
|
567
|
-
backgroundColor: theme.colors.background,
|
|
568
|
-
paddingVertical: moderateScale(10),
|
|
569
|
-
borderBottomWidth: 0.5,
|
|
570
|
-
borderBottomColor: theme.colors.border,
|
|
571
|
-
},
|
|
572
|
-
memberInfo: {
|
|
573
|
-
flexDirection: 'row',
|
|
574
|
-
alignItems: 'center',
|
|
575
|
-
flex: 1,
|
|
576
|
-
},
|
|
577
|
-
memberAvatar: {
|
|
578
|
-
width: moderateScale(45),
|
|
579
|
-
height: moderateScale(45),
|
|
580
|
-
borderRadius: moderateScale(22.5),
|
|
581
|
-
marginRight: theme.spacing.md,
|
|
582
|
-
overflow: 'hidden',
|
|
583
|
-
},
|
|
584
|
-
avatarImage: {
|
|
585
|
-
width: '100%',
|
|
586
|
-
height: '100%',
|
|
587
|
-
resizeMode: 'cover',
|
|
588
|
-
},
|
|
589
|
-
avatarPlaceholder: {
|
|
590
|
-
width: '100%',
|
|
591
|
-
height: '100%',
|
|
592
|
-
backgroundColor: theme.colors.surface,
|
|
593
|
-
alignItems: 'center',
|
|
594
|
-
justifyContent: 'center',
|
|
595
|
-
},
|
|
596
|
-
memberName: {
|
|
597
|
-
fontFamily: Fonts.outfitRegular,
|
|
598
|
-
fontSize: moderateScale(16),
|
|
599
|
-
color: theme.colors.text,
|
|
600
|
-
},
|
|
601
|
-
ticketBadge: {
|
|
602
|
-
paddingHorizontal: theme.spacing.sm,
|
|
603
|
-
paddingVertical: theme.spacing.xs,
|
|
604
|
-
},
|
|
605
|
-
ticketCount: {
|
|
606
|
-
fontFamily: Fonts.outfitMedium,
|
|
607
|
-
fontSize: moderateScale(14),
|
|
608
|
-
color: theme.colors.blue,
|
|
609
|
-
},
|
|
610
|
-
// Footer
|
|
611
|
-
footerContainer: {
|
|
612
|
-
paddingHorizontal: theme.spacing.lg,
|
|
613
|
-
paddingTop: theme.spacing.lg,
|
|
614
|
-
paddingBottom: theme.spacing.md,
|
|
615
|
-
},
|
|
616
|
-
referButton: {
|
|
617
|
-
borderColor: theme.colors.blue,
|
|
618
|
-
backgroundColor: 'transparent',
|
|
619
|
-
marginTop: theme.spacing.sm,
|
|
620
|
-
},
|
|
621
|
-
referButtonText: {
|
|
622
|
-
color: theme.colors.blue,
|
|
623
|
-
fontFamily: Fonts.outfitMedium,
|
|
624
|
-
},
|
|
625
|
-
// Loading and error states
|
|
626
|
-
footerLoader: {
|
|
627
|
-
paddingVertical: theme.spacing.md,
|
|
628
|
-
alignItems: 'center',
|
|
629
|
-
justifyContent: 'center',
|
|
630
|
-
},
|
|
631
|
-
emptyContainer: {
|
|
632
|
-
flex: 1,
|
|
633
|
-
alignItems: 'center',
|
|
634
|
-
justifyContent: 'center',
|
|
635
|
-
paddingVertical: moderateScale(60),
|
|
636
|
-
paddingHorizontal: theme.spacing.xl,
|
|
637
|
-
},
|
|
638
|
-
emptyText: {
|
|
639
|
-
fontFamily: Fonts.outfitMedium,
|
|
640
|
-
fontSize: moderateScale(16),
|
|
641
|
-
color: theme.colors.text,
|
|
642
|
-
textAlign: 'center',
|
|
643
|
-
marginBottom: theme.spacing.xs,
|
|
644
|
-
},
|
|
645
|
-
emptySubText: {
|
|
646
|
-
fontFamily: Fonts.outfitRegular,
|
|
647
|
-
fontSize: moderateScale(14),
|
|
648
|
-
color: theme.colors.textSecondary,
|
|
649
|
-
textAlign: 'center',
|
|
650
|
-
},
|
|
651
|
-
errorText: {
|
|
652
|
-
fontFamily: Fonts.outfitMedium,
|
|
653
|
-
fontSize: moderateScale(16),
|
|
654
|
-
color: theme.colors.error,
|
|
655
|
-
textAlign: 'center',
|
|
656
|
-
marginBottom: theme.spacing.xs,
|
|
657
|
-
},
|
|
658
|
-
errorSubText: {
|
|
659
|
-
fontFamily: Fonts.outfitRegular,
|
|
660
|
-
fontSize: moderateScale(14),
|
|
661
|
-
color: theme.colors.textSecondary,
|
|
662
|
-
textAlign: 'center',
|
|
663
|
-
marginBottom: theme.spacing.md,
|
|
664
|
-
},
|
|
665
|
-
retryButton: {
|
|
666
|
-
paddingHorizontal: theme.spacing.lg,
|
|
667
|
-
paddingVertical: theme.spacing.sm,
|
|
668
|
-
backgroundColor: theme.colors.blue,
|
|
669
|
-
borderRadius: theme.borderRadius.md,
|
|
670
|
-
marginTop: theme.spacing.sm,
|
|
671
|
-
},
|
|
672
|
-
retryButtonText: {
|
|
673
|
-
fontFamily: Fonts.outfitMedium,
|
|
674
|
-
fontSize: moderateScale(14),
|
|
675
|
-
color: theme.colors.white,
|
|
676
|
-
},
|
|
677
|
-
// Modal styles
|
|
678
|
-
modalOverlay: {
|
|
679
|
-
flex: 1,
|
|
680
|
-
justifyContent: 'flex-end',
|
|
681
|
-
},
|
|
682
|
-
modalBackdrop: {
|
|
683
|
-
position: 'absolute',
|
|
684
|
-
top: 0,
|
|
685
|
-
left: 0,
|
|
686
|
-
right: 0,
|
|
687
|
-
bottom: 0,
|
|
688
|
-
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
689
|
-
},
|
|
690
|
-
modalContainer: {
|
|
691
|
-
backgroundColor: theme.colors.white,
|
|
692
|
-
borderTopLeftRadius: moderateScale(20),
|
|
693
|
-
borderTopRightRadius: moderateScale(20),
|
|
694
|
-
paddingHorizontal: theme.spacing.lg,
|
|
695
|
-
paddingTop: theme.spacing.sm,
|
|
696
|
-
paddingBottom: theme.spacing.xl,
|
|
697
|
-
height: '60%',
|
|
698
|
-
maxHeight: '60%',
|
|
699
|
-
},
|
|
700
|
-
dragHandle: {
|
|
701
|
-
width: moderateScale(40),
|
|
702
|
-
height: moderateScale(4),
|
|
703
|
-
backgroundColor: theme.colors.border,
|
|
704
|
-
borderRadius: moderateScale(2),
|
|
705
|
-
alignSelf: 'center',
|
|
706
|
-
marginBottom: theme.spacing.sm,
|
|
707
|
-
},
|
|
708
|
-
modalHeader: {
|
|
709
|
-
paddingVertical: theme.spacing.md,
|
|
710
|
-
borderBottomColor: theme.colors.border,
|
|
711
|
-
},
|
|
712
|
-
modalTitle: {
|
|
713
|
-
fontFamily: Fonts.outfitSemiBold,
|
|
714
|
-
fontSize: moderateScale(18),
|
|
715
|
-
color: theme.colors.text,
|
|
716
|
-
},
|
|
717
|
-
modalSubtitle: {
|
|
718
|
-
fontFamily: Fonts.outfitRegular,
|
|
719
|
-
fontSize: moderateScale(14),
|
|
720
|
-
color: theme.colors.textSecondary,
|
|
721
|
-
textAlign: 'center',
|
|
722
|
-
marginTop: theme.spacing.xs,
|
|
723
|
-
},
|
|
724
|
-
ticketListContent: {
|
|
725
|
-
paddingVertical: theme.spacing.sm,
|
|
726
|
-
},
|
|
727
|
-
ticketNumberBadge: {
|
|
728
|
-
flex: 1,
|
|
729
|
-
margin: moderateScale(5),
|
|
730
|
-
paddingVertical: moderateScale(12),
|
|
731
|
-
paddingHorizontal: moderateScale(8),
|
|
732
|
-
backgroundColor: theme.colors.lightLavenderGray,
|
|
733
|
-
borderRadius: theme.borderRadius.md,
|
|
734
|
-
alignItems: 'center',
|
|
735
|
-
justifyContent: 'center',
|
|
736
|
-
minWidth: moderateScale(90),
|
|
737
|
-
},
|
|
738
|
-
ticketNumberText: {
|
|
739
|
-
fontFamily: Fonts.outfitMedium,
|
|
740
|
-
fontSize: moderateScale(16),
|
|
741
|
-
color: theme.colors.blue,
|
|
742
|
-
},
|
|
743
|
-
emptyTicketContainer: {
|
|
744
|
-
flex: 1,
|
|
745
|
-
alignItems: 'center',
|
|
746
|
-
justifyContent: 'center',
|
|
747
|
-
paddingVertical: moderateScale(40),
|
|
748
|
-
},
|
|
749
|
-
emptyTicketText: {
|
|
750
|
-
fontFamily: Fonts.outfitMedium,
|
|
751
|
-
fontSize: moderateScale(14),
|
|
752
|
-
color: theme.colors.textSecondary,
|
|
753
|
-
textAlign: 'center',
|
|
754
|
-
},
|
|
755
|
-
closeButton: {
|
|
756
|
-
marginTop: theme.spacing.md,
|
|
757
|
-
},
|
|
758
|
-
});
|