|
@@ -6,11 +6,19 @@ import {
|
|
|
TouchableOpacity,
|
|
|
ScrollView,
|
|
|
LayoutAnimation,
|
|
|
- findNodeHandle
|
|
|
+ Modal
|
|
|
} from 'react-native';
|
|
|
import { FlashList } from '@shopify/flash-list';
|
|
|
import { CommonActions, useFocusEffect, useNavigation } from '@react-navigation/native';
|
|
|
-import { styles } from './styles';
|
|
|
+import { popupStyles, styles } from './styles';
|
|
|
+import Animated, {
|
|
|
+ useSharedValue,
|
|
|
+ useAnimatedStyle,
|
|
|
+ withTiming,
|
|
|
+ runOnJS,
|
|
|
+ interpolate,
|
|
|
+ Extrapolation
|
|
|
+} from 'react-native-reanimated';
|
|
|
|
|
|
import { NAVIGATION_PAGES } from 'src/types';
|
|
|
import { StoreType, storage } from 'src/storage';
|
|
@@ -24,13 +32,40 @@ import EarthIcon from 'assets/icons/travels-section/earth.svg';
|
|
|
import NomadsIcon from 'assets/icons/bottom-navigation/travellers.svg';
|
|
|
import CalendarPlusIcon from 'assets/icons/events/calendar-plus.svg';
|
|
|
import ShoppingCartIcon from 'assets/icons/events/shopping-cart.svg';
|
|
|
-import { SingleEvent, useGetCanAddEventQuery, useGetEventsListQuery } from '@api/events';
|
|
|
+import StarIcon from 'assets/icons/events/star.svg';
|
|
|
+
|
|
|
+import {
|
|
|
+ PostGetEventsListReturn,
|
|
|
+ SingleEvent,
|
|
|
+ useGetCanAddEventQuery,
|
|
|
+ useGetEventsListQuery
|
|
|
+} from '@api/events';
|
|
|
import moment from 'moment';
|
|
|
import { API_HOST } from 'src/constants';
|
|
|
import { Grayscale } from 'react-native-color-matrix-image-filters';
|
|
|
import { renderSpotsText } from './utils';
|
|
|
import ChevronIcon from 'assets/icons/chevron-left.svg';
|
|
|
import Tooltip from 'react-native-walkthrough-tooltip';
|
|
|
+import { TabBar, TabView } from 'react-native-tab-view';
|
|
|
+
|
|
|
+function TabViewDelayed({
|
|
|
+ children,
|
|
|
+ waitBeforeShow = 0
|
|
|
+}: {
|
|
|
+ children: React.ReactNode;
|
|
|
+ waitBeforeShow?: number;
|
|
|
+}) {
|
|
|
+ const [isShown, setIsShown] = useState(false);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ const timer = setTimeout(() => {
|
|
|
+ setIsShown(true);
|
|
|
+ }, waitBeforeShow);
|
|
|
+ return () => clearTimeout(timer);
|
|
|
+ }, [waitBeforeShow]);
|
|
|
+
|
|
|
+ return isShown ? children : null;
|
|
|
+}
|
|
|
|
|
|
const EventsScreen = () => {
|
|
|
const token = (storage.get('token', StoreType.STRING) as string) ?? null;
|
|
@@ -39,44 +74,156 @@ const EventsScreen = () => {
|
|
|
const { data: canAddEvent } = useGetCanAddEventQuery(token, true);
|
|
|
const navigation = useNavigation();
|
|
|
const [searchQuery, setSearchQuery] = useState('');
|
|
|
- const [events, setEvents] = useState<SingleEvent[]>([]);
|
|
|
- const [pastEvents, setPastEvents] = useState<SingleEvent[]>([]);
|
|
|
- const [filteredEvents, setFilteredEvents] = useState<SingleEvent[]>([]);
|
|
|
- const [filteredPastEvents, setFilteredPastEvents] = useState<SingleEvent[]>([]);
|
|
|
+ const [events, setEvents] = useState<PostGetEventsListReturn>({
|
|
|
+ data: [],
|
|
|
+ nm: [],
|
|
|
+ community: []
|
|
|
+ } as never);
|
|
|
+ const [pastEvents, setPastEvents] = useState<PostGetEventsListReturn>({
|
|
|
+ data: [],
|
|
|
+ nm: [],
|
|
|
+ community: []
|
|
|
+ } as never);
|
|
|
+ const [filteredEvents, setFilteredEvents] = useState<PostGetEventsListReturn>({
|
|
|
+ data: [],
|
|
|
+ nm: [],
|
|
|
+ community: []
|
|
|
+ } as never);
|
|
|
+ const [filteredPastEvents, setFilteredPastEvents] = useState<PostGetEventsListReturn>({
|
|
|
+ data: [],
|
|
|
+ nm: [],
|
|
|
+ community: []
|
|
|
+ } as never);
|
|
|
const [tooltipStates, setTooltipStates] = useState<Record<number, boolean>>({});
|
|
|
const date = new Date();
|
|
|
|
|
|
- const [isExpanded, setIsExpanded] = useState(false);
|
|
|
- const scrollViewRef = useRef<ScrollView>(null);
|
|
|
+ const [expandedStates, setExpandedStates] = useState<Record<string, boolean>>({
|
|
|
+ nm: false,
|
|
|
+ community: false,
|
|
|
+ data: false
|
|
|
+ });
|
|
|
+
|
|
|
+ const scrollViewRefs = useRef<Record<string, FlashList<SingleEvent> | null>>({
|
|
|
+ nm: null,
|
|
|
+ community: null,
|
|
|
+ data: null
|
|
|
+ });
|
|
|
const sectionRef = useRef<View>(null);
|
|
|
|
|
|
- const toggleExpand = () => {
|
|
|
+ const [showPopup, setShowPopup] = useState(false);
|
|
|
+ const [popupPosition, setPopupPosition] = useState({ x: 0, y: 0 });
|
|
|
+
|
|
|
+ const buttonRef = useRef<TouchableOpacity>(null);
|
|
|
+
|
|
|
+ const [index, setIndex] = useState<number>(0);
|
|
|
+ const [routes] = useState<{ key: 'nm' | 'community' | 'data'; title: string }[]>([
|
|
|
+ { key: 'nm', title: 'NomadMania Events' },
|
|
|
+ { key: 'community', title: 'Community Events' },
|
|
|
+ { key: 'data', title: 'All Events' }
|
|
|
+ ]);
|
|
|
+
|
|
|
+ const SEARCH_CONTAINER_HEIGHT = 44;
|
|
|
+ const searchContainerHeight = useSharedValue(SEARCH_CONTAINER_HEIGHT);
|
|
|
+ const lastScrollY = useRef(0);
|
|
|
+ const isSearchVisible = useRef(true);
|
|
|
+
|
|
|
+ const hideSearchContainer = useCallback(() => {
|
|
|
+ 'worklet';
|
|
|
+ if (isSearchVisible.current) {
|
|
|
+ isSearchVisible.current = false;
|
|
|
+ searchContainerHeight.value = withTiming(0, {
|
|
|
+ duration: 150
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const showSearchContainer = useCallback(() => {
|
|
|
+ 'worklet';
|
|
|
+ if (!isSearchVisible.current) {
|
|
|
+ isSearchVisible.current = true;
|
|
|
+ searchContainerHeight.value = withTiming(SEARCH_CONTAINER_HEIGHT, {
|
|
|
+ duration: 150
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const handleScroll = useCallback(
|
|
|
+ (event: any) => {
|
|
|
+ const currentScrollY = event.nativeEvent.contentOffset.y;
|
|
|
+ const diff = currentScrollY - lastScrollY.current;
|
|
|
+
|
|
|
+ if (diff > 3 && currentScrollY > 20 && isSearchVisible.current) {
|
|
|
+ runOnJS(hideSearchContainer)();
|
|
|
+ } else if (currentScrollY <= 5 && !isSearchVisible.current) {
|
|
|
+ runOnJS(showSearchContainer)();
|
|
|
+ }
|
|
|
+
|
|
|
+ lastScrollY.current = currentScrollY;
|
|
|
+ },
|
|
|
+ [hideSearchContainer, showSearchContainer]
|
|
|
+ );
|
|
|
+
|
|
|
+ const searchContainerAnimatedStyle = useAnimatedStyle(() => {
|
|
|
+ return {
|
|
|
+ height: searchContainerHeight.value,
|
|
|
+ overflow: 'hidden',
|
|
|
+ opacity: interpolate(
|
|
|
+ searchContainerHeight.value,
|
|
|
+ [0, SEARCH_CONTAINER_HEIGHT],
|
|
|
+ [0, 1],
|
|
|
+ Extrapolation.CLAMP
|
|
|
+ )
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ const handleAddButtonPress = () => {
|
|
|
+ if (buttonRef.current) {
|
|
|
+ buttonRef.current.measure((x, y, width, height, pageX, pageY) => {
|
|
|
+ setPopupPosition({
|
|
|
+ x: pageX - 120,
|
|
|
+ y: pageY + height + 5
|
|
|
+ });
|
|
|
+ setShowPopup(true);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handlePopupOption = (option: 'meeting' | 'trip') => {
|
|
|
+ setShowPopup(false);
|
|
|
+
|
|
|
+ if (option === 'meeting') {
|
|
|
+ navigation.navigate(NAVIGATION_PAGES.CREATE_EVENT as never);
|
|
|
+ } else if (option === 'trip') {
|
|
|
+ navigation.navigate(NAVIGATION_PAGES.CREATE_SHARED_TRIP as never);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const toggleExpand = (tabKey: string) => {
|
|
|
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut, () => {
|
|
|
- if (!isExpanded && sectionRef.current && scrollViewRef.current) {
|
|
|
- sectionRef.current.measureLayout(
|
|
|
- findNodeHandle(scrollViewRef.current)!,
|
|
|
- (x, y) => {
|
|
|
- scrollViewRef.current?.scrollTo({ y, animated: true });
|
|
|
- },
|
|
|
- () => console.warn('events measureLayout error')
|
|
|
- );
|
|
|
+ if (!expandedStates[tabKey] && sectionRef.current && scrollViewRefs.current[tabKey]) {
|
|
|
+ scrollViewRefs.current[tabKey]?.scrollToEnd({
|
|
|
+ animated: true
|
|
|
+ });
|
|
|
}
|
|
|
});
|
|
|
|
|
|
- setIsExpanded(!isExpanded);
|
|
|
+ setExpandedStates((prev) => ({
|
|
|
+ ...prev,
|
|
|
+ [tabKey]: !prev[tabKey]
|
|
|
+ }));
|
|
|
};
|
|
|
|
|
|
useEffect(() => {
|
|
|
if (data && data.data) {
|
|
|
- setEvents(data.data);
|
|
|
- setFilteredEvents(data.data);
|
|
|
+ setEvents(data);
|
|
|
+ setFilteredEvents(data);
|
|
|
}
|
|
|
}, [data]);
|
|
|
|
|
|
useEffect(() => {
|
|
|
if (pastData && pastData.data) {
|
|
|
- setPastEvents(pastData.data);
|
|
|
- setFilteredPastEvents(pastData.data);
|
|
|
+ setPastEvents(pastData);
|
|
|
+ setFilteredPastEvents(pastData);
|
|
|
}
|
|
|
}, [pastData]);
|
|
|
|
|
@@ -89,20 +236,36 @@ const EventsScreen = () => {
|
|
|
const handleSearch = (text: string) => {
|
|
|
if (text) {
|
|
|
const searchData =
|
|
|
- events.filter((item: any) => {
|
|
|
- const itemData = item.name ? item.name.toLowerCase() : ''.toLowerCase();
|
|
|
- const textData = text.toLowerCase();
|
|
|
- return itemData.indexOf(textData) > -1;
|
|
|
- }) ?? [];
|
|
|
- setFilteredEvents(searchData);
|
|
|
+ (index === 0 ? events.nm : index === 1 ? events.community : events.data).filter(
|
|
|
+ (item: any) => {
|
|
|
+ const itemData = item.name ? item.name.toLowerCase() : ''.toLowerCase();
|
|
|
+ const textData = text.toLowerCase();
|
|
|
+ return itemData.indexOf(textData) > -1;
|
|
|
+ }
|
|
|
+ ) ?? [];
|
|
|
+ setFilteredEvents(
|
|
|
+ index === 0
|
|
|
+ ? { ...events, nm: searchData }
|
|
|
+ : index === 1
|
|
|
+ ? { ...events, community: searchData }
|
|
|
+ : { ...events, data: searchData }
|
|
|
+ );
|
|
|
|
|
|
const searchPastData =
|
|
|
- pastEvents.filter((item: any) => {
|
|
|
- const itemData = item.name ? item.name.toLowerCase() : ''.toLowerCase();
|
|
|
- const textData = text.toLowerCase();
|
|
|
- return itemData.indexOf(textData) > -1;
|
|
|
- }) ?? [];
|
|
|
- setFilteredPastEvents(searchPastData);
|
|
|
+ (index === 0 ? pastEvents.nm : index === 1 ? pastEvents.community : pastEvents.data).filter(
|
|
|
+ (item: any) => {
|
|
|
+ const itemData = item.name ? item.name.toLowerCase() : ''.toLowerCase();
|
|
|
+ const textData = text.toLowerCase();
|
|
|
+ return itemData.indexOf(textData) > -1;
|
|
|
+ }
|
|
|
+ ) ?? [];
|
|
|
+ setFilteredPastEvents(
|
|
|
+ index === 0
|
|
|
+ ? { ...events, nm: searchPastData }
|
|
|
+ : index === 1
|
|
|
+ ? { ...events, community: searchPastData }
|
|
|
+ : { ...events, data: searchPastData }
|
|
|
+ );
|
|
|
|
|
|
setSearchQuery(text);
|
|
|
} else {
|
|
@@ -114,8 +277,17 @@ const EventsScreen = () => {
|
|
|
|
|
|
const formatEventDate = (event: SingleEvent) => {
|
|
|
if (event.date_from && event.date_to) {
|
|
|
+ if (event.date_tentative) {
|
|
|
+ return `${moment(event.date_from, 'YYYY-MM').format('MMM YYYY')} - ${moment(
|
|
|
+ event.date_to,
|
|
|
+ 'YYYY-MM'
|
|
|
+ ).format('MMM YYYY')}`;
|
|
|
+ }
|
|
|
return `${moment(event.date_from, 'YYYY-MM-DD').format('DD MMM YYYY')} - ${moment(event.date_to, 'YYYY-MM-DD').format('DD MMM YYYY')}`;
|
|
|
} else {
|
|
|
+ if (event.date_tentative) {
|
|
|
+ return `${moment(event.date, 'YYYY-MM').format('MMM YYYY')}`;
|
|
|
+ }
|
|
|
return moment(event.date, 'YYYY-MM-DD').format('DD MMMM YYYY');
|
|
|
}
|
|
|
};
|
|
@@ -138,7 +310,7 @@ const EventsScreen = () => {
|
|
|
}
|
|
|
|
|
|
const photo = item.photo
|
|
|
- ? API_HOST + '/webapi/events/get-square-photo/' + item.id + '?cacheBust=' + date
|
|
|
+ ? API_HOST + '/webapi/events/get-square-photo/' + item.id
|
|
|
: API_HOST + staticImgUrl;
|
|
|
|
|
|
return (
|
|
@@ -156,13 +328,17 @@ const EventsScreen = () => {
|
|
|
disabled={item.active === 0}
|
|
|
>
|
|
|
<View style={styles.imageWrapper}>
|
|
|
- <Image source={{ uri: photo }} style={styles.image} resizeMode="cover" />
|
|
|
+ <Image
|
|
|
+ source={{ uri: photo, cache: 'reload' }}
|
|
|
+ style={styles.image}
|
|
|
+ resizeMode="cover"
|
|
|
+ />
|
|
|
|
|
|
- {/* {item.isPaid && (
|
|
|
- <View style={styles.iconOverlay}>
|
|
|
- <ShoppingCartIcon fill={Colors.WHITE} width={12} />
|
|
|
- </View>
|
|
|
- )} */}
|
|
|
+ {item.star === 1 && (
|
|
|
+ <View style={styles.iconOverlay}>
|
|
|
+ <StarIcon fill={Colors.WHITE} width={12} />
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
|
|
|
{item.joined && token ? (
|
|
|
<View style={styles.joinedOverlay}>
|
|
@@ -241,7 +417,7 @@ const EventsScreen = () => {
|
|
|
)}
|
|
|
</View>
|
|
|
|
|
|
- {item.type !== 1 || item.full ? (
|
|
|
+ {item.type === 2 || item.type === 3 || item.full ? (
|
|
|
<View
|
|
|
style={[
|
|
|
styles.statusBadge,
|
|
@@ -258,6 +434,73 @@ const EventsScreen = () => {
|
|
|
);
|
|
|
};
|
|
|
|
|
|
+ const renderScene = ({
|
|
|
+ route
|
|
|
+ }: {
|
|
|
+ route: { key: 'nm' | 'community' | 'data'; title: string };
|
|
|
+ }) => {
|
|
|
+ const isCurrentTabExpanded = expandedStates[route.key];
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <FlashList
|
|
|
+ ref={(ref) => {
|
|
|
+ scrollViewRefs.current[route.key] = ref;
|
|
|
+ }}
|
|
|
+ data={filteredEvents[route.key] || []}
|
|
|
+ scrollEnabled={true}
|
|
|
+ keyExtractor={(item) => `${route.key}-${item.id}`}
|
|
|
+ renderItem={renderEventCard}
|
|
|
+ estimatedItemSize={120}
|
|
|
+ contentContainerStyle={styles.listContainer}
|
|
|
+ showsVerticalScrollIndicator={false}
|
|
|
+ onScroll={handleScroll}
|
|
|
+ scrollEventThrottle={16}
|
|
|
+ ListFooterComponent={
|
|
|
+ filteredPastEvents[route.key] && filteredPastEvents[route.key].length ? (
|
|
|
+ <View ref={sectionRef} style={styles.sectionContainer}>
|
|
|
+ <TouchableOpacity onPress={() => toggleExpand(route.key)} style={styles.header}>
|
|
|
+ <View style={styles.headerContainer}>
|
|
|
+ <Text style={styles.headerText}>Past Events</Text>
|
|
|
+ </View>
|
|
|
+
|
|
|
+ <View style={styles.chevronContainer}>
|
|
|
+ <ChevronIcon
|
|
|
+ fill={Colors.DARK_BLUE}
|
|
|
+ style={[styles.headerIcon, isCurrentTabExpanded ? styles.rotate : null]}
|
|
|
+ />
|
|
|
+ </View>
|
|
|
+ </TouchableOpacity>
|
|
|
+
|
|
|
+ {isCurrentTabExpanded ? (
|
|
|
+ <FlashList
|
|
|
+ data={filteredPastEvents[route.key] || []}
|
|
|
+ scrollEnabled={true}
|
|
|
+ keyExtractor={(item) => item.id.toString()}
|
|
|
+ renderItem={renderEventCard}
|
|
|
+ estimatedItemSize={100}
|
|
|
+ contentContainerStyle={styles.listContainer}
|
|
|
+ showsVerticalScrollIndicator={false}
|
|
|
+ />
|
|
|
+ ) : null}
|
|
|
+ </View>
|
|
|
+ ) : null
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </>
|
|
|
+ );
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleIndexChange = useCallback(
|
|
|
+ (newIndex: number) => {
|
|
|
+ setSearchQuery('');
|
|
|
+ if (newIndex >= 0 && newIndex < routes.length) {
|
|
|
+ setIndex(newIndex);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ [routes.length]
|
|
|
+ );
|
|
|
+
|
|
|
return (
|
|
|
<PageWrapper>
|
|
|
<Header
|
|
@@ -265,8 +508,10 @@ const EventsScreen = () => {
|
|
|
rightElement={
|
|
|
canAddEvent?.can ? (
|
|
|
<TouchableOpacity
|
|
|
- onPress={() => navigation.navigate(NAVIGATION_PAGES.CREATE_EVENT as never)}
|
|
|
+ ref={buttonRef}
|
|
|
+ onPress={handleAddButtonPress}
|
|
|
style={{ width: 30 }}
|
|
|
+ hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
|
|
>
|
|
|
<CalendarPlusIcon fill={Colors.DARK_BLUE} />
|
|
|
</TouchableOpacity>
|
|
@@ -274,58 +519,94 @@ const EventsScreen = () => {
|
|
|
}
|
|
|
/>
|
|
|
|
|
|
- <ScrollView ref={scrollViewRef} nestedScrollEnabled showsVerticalScrollIndicator={false}>
|
|
|
- <View style={styles.searchContainer}>
|
|
|
- <Input
|
|
|
- inputMode={'search'}
|
|
|
- placeholder={'Search'}
|
|
|
- onChange={(text) => handleSearch(text)}
|
|
|
- value={searchQuery}
|
|
|
- icon={<SearchIcon fill={'#C8C8C8'} width={14} height={14} />}
|
|
|
- height={38}
|
|
|
- />
|
|
|
- </View>
|
|
|
-
|
|
|
- <FlashList
|
|
|
- data={filteredEvents}
|
|
|
- scrollEnabled={false}
|
|
|
- keyExtractor={(item) => item.id.toString()}
|
|
|
- renderItem={renderEventCard}
|
|
|
- estimatedItemSize={100}
|
|
|
- contentContainerStyle={styles.listContainer}
|
|
|
- showsVerticalScrollIndicator={false}
|
|
|
- extraData={tooltipStates}
|
|
|
+ {/* <ScrollView
|
|
|
+ ref={scrollViewRef}
|
|
|
+ nestedScrollEnabled
|
|
|
+ showsVerticalScrollIndicator={false}
|
|
|
+ style={{ flex: 1, height: '100%' }}
|
|
|
+ > */}
|
|
|
+ <Animated.View style={[styles.searchContainer, searchContainerAnimatedStyle]}>
|
|
|
+ <Input
|
|
|
+ inputMode={'search'}
|
|
|
+ placeholder={'Search'}
|
|
|
+ onChange={(text) => handleSearch(text)}
|
|
|
+ value={searchQuery}
|
|
|
+ icon={<SearchIcon fill={'#C8C8C8'} width={14} height={14} />}
|
|
|
+ height={38}
|
|
|
/>
|
|
|
+ </Animated.View>
|
|
|
|
|
|
- {filteredPastEvents && filteredPastEvents.length ? (
|
|
|
- <View ref={sectionRef} style={styles.sectionContainer}>
|
|
|
- <TouchableOpacity onPress={toggleExpand} style={styles.header}>
|
|
|
- <View style={styles.headerContainer}>
|
|
|
- <Text style={styles.headerText}>Past Events</Text>
|
|
|
- </View>
|
|
|
+ {/* <TabViewDelayed waitBeforeShow={300}> */}
|
|
|
+ <TabView
|
|
|
+ navigationState={{ index, routes }}
|
|
|
+ renderScene={renderScene}
|
|
|
+ onIndexChange={handleIndexChange}
|
|
|
+ lazy={false}
|
|
|
+ swipeEnabled={true}
|
|
|
+ renderTabBar={(props) => (
|
|
|
+ <TabBar
|
|
|
+ {...props}
|
|
|
+ indicatorStyle={{ backgroundColor: Colors.DARK_BLUE }}
|
|
|
+ style={styles.tabBar}
|
|
|
+ tabStyle={styles.tabStyle}
|
|
|
+ pressColor={'transparent'}
|
|
|
+ renderLabel={({ route, focused }) => (
|
|
|
+ <Text
|
|
|
+ style={[
|
|
|
+ styles.tabLabel,
|
|
|
+ { color: Colors.DARK_BLUE, opacity: focused ? 1 : 0.4, textAlign: 'center' }
|
|
|
+ ]}
|
|
|
+ numberOfLines={2}
|
|
|
+ adjustsFontSizeToFit={true}
|
|
|
+ minimumFontScale={0.8}
|
|
|
+ >
|
|
|
+ {route.title}
|
|
|
+ </Text>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ />
|
|
|
+ {/* </TabViewDelayed> */}
|
|
|
+ {/* </ScrollView> */}
|
|
|
|
|
|
- <View style={styles.chevronContainer}>
|
|
|
- <ChevronIcon
|
|
|
- fill={Colors.DARK_BLUE}
|
|
|
- style={[styles.headerIcon, isExpanded ? styles.rotate : null]}
|
|
|
- />
|
|
|
- </View>
|
|
|
+ <Modal
|
|
|
+ visible={showPopup}
|
|
|
+ transparent={true}
|
|
|
+ animationType="fade"
|
|
|
+ onRequestClose={() => setShowPopup(false)}
|
|
|
+ >
|
|
|
+ <TouchableOpacity
|
|
|
+ style={{
|
|
|
+ flex: 1,
|
|
|
+ backgroundColor: 'rgba(0,0,0,0.1)'
|
|
|
+ }}
|
|
|
+ onPress={() => setShowPopup(false)}
|
|
|
+ activeOpacity={1}
|
|
|
+ >
|
|
|
+ <View
|
|
|
+ style={[
|
|
|
+ popupStyles.popup,
|
|
|
+ {
|
|
|
+ top: popupPosition.y,
|
|
|
+ left: popupPosition.x
|
|
|
+ }
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ <TouchableOpacity
|
|
|
+ style={popupStyles.popupOption}
|
|
|
+ onPress={() => handlePopupOption('meeting')}
|
|
|
+ >
|
|
|
+ <Text style={popupStyles.popupText}>Add meeting</Text>
|
|
|
+ </TouchableOpacity>
|
|
|
+ <TouchableOpacity
|
|
|
+ style={[popupStyles.popupOption, popupStyles.popupOptionLast]}
|
|
|
+ onPress={() => handlePopupOption('trip')}
|
|
|
+ >
|
|
|
+ <Text style={popupStyles.popupText}>Add shared trip</Text>
|
|
|
</TouchableOpacity>
|
|
|
-
|
|
|
- {isExpanded ? (
|
|
|
- <FlashList
|
|
|
- data={filteredPastEvents}
|
|
|
- scrollEnabled={false}
|
|
|
- keyExtractor={(item) => item.id.toString()}
|
|
|
- renderItem={renderEventCard}
|
|
|
- estimatedItemSize={100}
|
|
|
- contentContainerStyle={styles.listContainer}
|
|
|
- showsVerticalScrollIndicator={false}
|
|
|
- />
|
|
|
- ) : null}
|
|
|
</View>
|
|
|
- ) : null}
|
|
|
- </ScrollView>
|
|
|
+ </TouchableOpacity>
|
|
|
+ </Modal>
|
|
|
</PageWrapper>
|
|
|
);
|
|
|
};
|