Files
cally/components/pages/calendar/EventCalendar.tsx
2025-02-02 22:28:40 +01:00

111 lines
3.8 KiB
TypeScript

import React from 'react';
import {StyleSheet, View, ActivityIndicator} from 'react-native';
import {Text} from 'react-native-ui-lib';
import Animated, {
withTiming,
useAnimatedStyle,
FadeOut,
useSharedValue,
} from 'react-native-reanimated';
import {useGetEvents} from '@/hooks/firebase/useGetEvents';
import {useCalSync} from '@/hooks/useCalSync';
import {useSyncEvents} from '@/hooks/useSyncOnScroll';
import {useAtom} from 'jotai';
import {modeAtom} from './atoms';
import {MonthCalendar} from "@/components/pages/calendar/MonthCalendar";
import DetailedCalendar from "@/components/pages/calendar/DetailedCalendar";
import * as Device from "expo-device";
export type CalendarMode = 'month' | 'day' | '3days' | 'week';
interface EventCalendarProps {
calendarWidth: number;
}
export const EventCalendar: React.FC<EventCalendarProps> = React.memo((props) => {
const {isLoading} = useGetEvents();
const [mode] = useAtom<CalendarMode>(modeAtom);
const {isSyncing} = useSyncEvents();
const isTablet = Device.deviceType === Device.DeviceType.TABLET;
const isCalendarReady = useSharedValue(false);
useCalSync();
const handleRenderComplete = React.useCallback(() => {
isCalendarReady.value = true;
}, []);
const containerStyle = useAnimatedStyle(() => ({
opacity: withTiming(isCalendarReady.value ? 1 : 0, {duration: 500}),
flex: 1,
}));
const monthStyle = useAnimatedStyle(() => ({
opacity: withTiming(mode === 'month' ? 1 : 0, {duration: 300}),
position: 'absolute',
width: '100%',
height: '100%',
}));
const detailedDayStyle = useAnimatedStyle(() => ({
opacity: withTiming(mode === 'day' ? 1 : 0, {duration: 300}),
position: 'absolute',
width: '100%',
height: '100%',
}));
const detailedMultiStyle = useAnimatedStyle(() => ({
opacity: withTiming(mode === (isTablet ? 'week' : '3days') ? 1 : 0, {duration: 300}),
position: 'absolute',
width: '100%',
height: '100%',
}));
return (
<View style={styles.root}>
{(isLoading || isSyncing) && mode !== 'month' && (
<Animated.View
exiting={FadeOut.duration(300)}
style={styles.loadingContainer}
>
{isSyncing && <Text>Syncing...</Text>}
<ActivityIndicator size="large" color="#0000ff"/>
</Animated.View>
)}
<Animated.View style={containerStyle}>
<Animated.View style={monthStyle} pointerEvents={mode === 'month' ? 'auto' : 'none'}>
<MonthCalendar/>
</Animated.View>
<Animated.View style={detailedDayStyle} pointerEvents={mode === 'day' ? 'auto' : 'none'}>
<DetailedCalendar mode="day" {...props} />
</Animated.View>
<Animated.View style={detailedMultiStyle}
pointerEvents={mode === (isTablet ? 'week' : '3days') ? 'auto' : 'none'}>
{!isLoading && (
<DetailedCalendar
onLoad={handleRenderComplete}
mode={isTablet ? 'week' : '3days'}
{...props}
/>
)}
</Animated.View>
</Animated.View>
</View>
);
});
const styles = StyleSheet.create({
root: {
flex: 1,
},
loadingContainer: {
position: 'absolute',
width: '100%',
height: '100%',
justifyContent: 'center',
alignItems: 'center',
zIndex: 100,
backgroundColor: 'rgba(255, 255, 255, 0.9)',
},
});
export default EventCalendar;