mirror of
https://github.com/urosran/cally.git
synced 2025-11-26 08:24:55 +00:00
fixed refresh, tablet drawer, drawer titles
This commit is contained in:
@ -2,7 +2,13 @@ import React, { useEffect } from "react";
|
||||
import { Drawer } from "expo-router/drawer";
|
||||
import { useSignOut } from "@/hooks/firebase/useSignOut";
|
||||
import { DrawerContentScrollView } from "@react-navigation/drawer";
|
||||
import { Button, ButtonSize, Text, View } from "react-native-ui-lib";
|
||||
import {
|
||||
Button,
|
||||
ButtonSize,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from "react-native-ui-lib";
|
||||
import { ImageBackground, StyleSheet } from "react-native";
|
||||
import DrawerButton from "@/components/shared/DrawerButton";
|
||||
import NavGroceryIcon from "@/assets/svgs/NavGroceryIcon";
|
||||
@ -11,7 +17,6 @@ import NavBrainDumpIcon from "@/assets/svgs/NavBrainDumpIcon";
|
||||
import NavCalendarIcon from "@/assets/svgs/NavCalendarIcon";
|
||||
import NavSettingsIcon from "@/assets/svgs/NavSettingsIcon";
|
||||
import ViewSwitch from "@/components/pages/(tablet_pages)/ViewSwitch";
|
||||
import { MaterialIcons } from "@expo/vector-icons";
|
||||
import { useSetAtom } from "jotai";
|
||||
import {
|
||||
isFamilyViewAtom,
|
||||
@ -23,6 +28,7 @@ import Ionicons from "@expo/vector-icons/Ionicons";
|
||||
import * as Device from "expo-device";
|
||||
import { DeviceType } from "expo-device";
|
||||
import FeedbackNavIcon from "@/assets/svgs/FeedbackNavIcon";
|
||||
import DrawerIcon from "@/assets/svgs/DrawerIcon";
|
||||
|
||||
export default function TabLayout() {
|
||||
const { mutateAsync: signOut } = useSignOut();
|
||||
@ -37,6 +43,20 @@ export default function TabLayout() {
|
||||
detachInactiveScreens
|
||||
screenOptions={({ navigation, route }) => ({
|
||||
headerShown: true,
|
||||
headerTitleAlign:
|
||||
Device.deviceType === DeviceType.TABLET ? "left" : "center",
|
||||
headerTitleStyle: {
|
||||
fontFamily: "Manrope_600SemiBold",
|
||||
fontSize: Device.deviceType === DeviceType.TABLET ? 22 : 17,
|
||||
},
|
||||
headerLeft: (props) => (
|
||||
<TouchableOpacity
|
||||
onPress={navigation.toggleDrawer}
|
||||
style={{ marginLeft: 16 }}
|
||||
>
|
||||
<DrawerIcon />
|
||||
</TouchableOpacity>
|
||||
),
|
||||
headerRight: () => {
|
||||
// Only show ViewSwitch on calendar and todos pages
|
||||
const showViewSwitch = ["calendar", "todos", "index"].includes(
|
||||
@ -48,9 +68,8 @@ export default function TabLayout() {
|
||||
</View>
|
||||
) : null;
|
||||
},
|
||||
headerStyle: { height: Device.deviceType === DeviceType.TABLET ? 100 : undefined},
|
||||
drawerStyle: {
|
||||
width: Device.deviceType === DeviceType.TABLET ? "50%" : "90%",
|
||||
width: Device.deviceType === DeviceType.TABLET ? "30%" : "90%",
|
||||
backgroundColor: "#f9f8f7",
|
||||
height: "100%",
|
||||
},
|
||||
@ -117,7 +136,7 @@ export default function TabLayout() {
|
||||
icon={<FeedbackNavIcon />}
|
||||
/>
|
||||
</View>
|
||||
<View style={{ flex: 1 }}>
|
||||
<View style={{ flex: 1, paddingRight: 0 }}>
|
||||
{/*<DrawerButton
|
||||
color="#fd1775"
|
||||
title={"My Reminders"}
|
||||
@ -233,14 +252,20 @@ export default function TabLayout() {
|
||||
name="index"
|
||||
options={{
|
||||
drawerLabel: "Calendar",
|
||||
title: "Calendar",
|
||||
title:
|
||||
Device.deviceType === DeviceType.TABLET
|
||||
? "Family Calendar"
|
||||
: "Calendar",
|
||||
}}
|
||||
/>
|
||||
<Drawer.Screen
|
||||
name="calendar"
|
||||
options={{
|
||||
drawerLabel: "Calendar",
|
||||
title: "Calendar",
|
||||
title:
|
||||
Device.deviceType === DeviceType.TABLET
|
||||
? "Family Calendar"
|
||||
: "Calendar",
|
||||
drawerItemStyle: { display: "none" },
|
||||
}}
|
||||
/>
|
||||
@ -276,7 +301,10 @@ export default function TabLayout() {
|
||||
name="todos"
|
||||
options={{
|
||||
drawerLabel: "To-Do",
|
||||
title: "To-Dos",
|
||||
title:
|
||||
Device.deviceType === DeviceType.TABLET
|
||||
? "Family To Do's"
|
||||
: "To Do's",
|
||||
}}
|
||||
/>
|
||||
<Drawer.Screen
|
||||
|
||||
@ -1,16 +1,26 @@
|
||||
import React, { useState } from "react";
|
||||
import { ScrollView, RefreshControl } from "react-native";
|
||||
import { useSetAtom } from "jotai";
|
||||
import { ScrollView, RefreshControl, View } from "react-native";
|
||||
import { useAtom } from "jotai";
|
||||
import CalendarPage from "@/components/pages/calendar/CalendarPage";
|
||||
import { refreshTriggerAtom } from "@/components/pages/calendar/atoms";
|
||||
import { colorMap } from "@/constants/colorMap";
|
||||
import TabletCalendarPage from "@/components/pages/(tablet_pages)/calendar/TabletCalendarPage";
|
||||
import { DeviceType } from "expo-device";
|
||||
import * as Device from "expo-device";
|
||||
import { useCalSync } from "@/hooks/useCalSync";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function Screen() {
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const setRefreshTrigger = useSetAtom(refreshTriggerAtom);
|
||||
const [shouldRefresh, setShouldRefresh] = useAtom(refreshTriggerAtom);
|
||||
|
||||
const {
|
||||
isConnectedToGoogle,
|
||||
isConnectedToMicrosoft,
|
||||
isConnectedToApple,
|
||||
resyncAllCalendars,
|
||||
isSyncing,
|
||||
} = useCalSync();
|
||||
|
||||
const onRefresh = React.useCallback(async () => {
|
||||
setRefreshing(true);
|
||||
@ -18,45 +28,65 @@ export default function Screen() {
|
||||
const minimumDelay = new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
|
||||
try {
|
||||
setRefreshTrigger((prev) => !prev);
|
||||
|
||||
await Promise.all([minimumDelay]);
|
||||
if (isConnectedToGoogle || isConnectedToMicrosoft || isConnectedToApple) {
|
||||
await Promise.all([resyncAllCalendars(), minimumDelay]);
|
||||
} else {
|
||||
await minimumDelay;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Refresh failed:", error);
|
||||
} finally {
|
||||
setRefreshing(false);
|
||||
setShouldRefresh((prev) => !prev);
|
||||
}
|
||||
}, [setRefreshTrigger]);
|
||||
|
||||
}, [
|
||||
resyncAllCalendars,
|
||||
isConnectedToGoogle,
|
||||
isConnectedToMicrosoft,
|
||||
isConnectedToApple,
|
||||
]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{Device.deviceType === DeviceType.TABLET ? (
|
||||
<TabletCalendarPage />
|
||||
) : (
|
||||
<ScrollView
|
||||
style={{ flex: 1 }}
|
||||
contentContainerStyle={{ flex: 1 }}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
colors={[
|
||||
colorMap.pink,
|
||||
colorMap.green,
|
||||
colorMap.orange,
|
||||
colorMap.purple,
|
||||
colorMap.teal,
|
||||
]}
|
||||
tintColor={colorMap.pink}
|
||||
progressBackgroundColor={"white"}
|
||||
refreshing={refreshing}
|
||||
onRefresh={onRefresh}
|
||||
/>
|
||||
}
|
||||
bounces={true}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
<CalendarPage />
|
||||
</ScrollView>
|
||||
)}
|
||||
</>
|
||||
<View style={{ flex: 1 }}>
|
||||
<View style={{ flex: 1, zIndex: -2 }}>
|
||||
{Device.deviceType === DeviceType.TABLET ? (
|
||||
<TabletCalendarPage />
|
||||
) : (
|
||||
<CalendarPage />
|
||||
)}
|
||||
</View>
|
||||
|
||||
<ScrollView
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: Device.deviceType === DeviceType.TABLET ? "15%" : 0,
|
||||
right: Device.deviceType === DeviceType.TABLET ? "25%" : 0,
|
||||
height: Device.deviceType === DeviceType.TABLET ? "9%" : "12%",
|
||||
width: Device.deviceType === DeviceType.TABLET ? "62%" : "100%",
|
||||
zIndex: 100,
|
||||
backgroundColor: "transparent",
|
||||
}}
|
||||
contentContainerStyle={{ flex: 1 }}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
colors={[
|
||||
colorMap.pink,
|
||||
colorMap.green,
|
||||
colorMap.orange,
|
||||
colorMap.purple,
|
||||
colorMap.teal,
|
||||
]}
|
||||
tintColor={colorMap.pink}
|
||||
progressBackgroundColor={"white"}
|
||||
refreshing={refreshing || isSyncing}
|
||||
onRefresh={onRefresh}
|
||||
/>
|
||||
}
|
||||
bounces={true}
|
||||
showsVerticalScrollIndicator={false}
|
||||
pointerEvents={refreshing || isSyncing ? "auto" : "none"}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
19
assets/svgs/DrawerIcon.tsx
Normal file
19
assets/svgs/DrawerIcon.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import * as React from "react"
|
||||
import Svg, { SvgProps, Path } from "react-native-svg"
|
||||
const DrawerIcon = (props: SvgProps) => (
|
||||
<Svg
|
||||
width={27}
|
||||
height={18}
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<Path
|
||||
stroke="#83807F"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2.7}
|
||||
d="M2 1.995h22.667M2 9.14h14.167M2 16.285h7.083"
|
||||
/>
|
||||
</Svg>
|
||||
)
|
||||
export default DrawerIcon
|
||||
@ -1,92 +1,88 @@
|
||||
import { Text, TouchableOpacity, View } from "react-native-ui-lib";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { SegmentedControl, View } from "react-native-ui-lib";
|
||||
import React, { memo, useCallback, useEffect, useRef, useState } from "react";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { NavigationProp } from "@react-navigation/native";
|
||||
import view from "react-native-ui-lib/src/components/view";
|
||||
import { NavigationProp, useNavigationState } from "@react-navigation/native";
|
||||
|
||||
interface ViewSwitchProps {
|
||||
navigation: NavigationProp<any>; // Adjust according to your navigation structure
|
||||
}
|
||||
|
||||
const ViewSwitch: React.FC<ViewSwitchProps> = ({ navigation }) => {
|
||||
const [pageIndex, setPageIndex] = useState<number>(navigation.getState().index);
|
||||
const ViewSwitch = memo(function ViewSwitch({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: any;
|
||||
}) {
|
||||
const isNavigating = useRef(false);
|
||||
const navigationState = useNavigationState((state) => state);
|
||||
const [selectedIndex, setSelectedIndex] = useState(
|
||||
navigationState.index === 6 ? 1 : 0
|
||||
);
|
||||
|
||||
// Sync the selected index with navigation state
|
||||
useEffect(() => {
|
||||
setPageIndex(navigation.getState().index);
|
||||
}, [navigation.getState().index])
|
||||
|
||||
return (
|
||||
<View
|
||||
row
|
||||
spread
|
||||
style={{
|
||||
borderRadius: 30,
|
||||
backgroundColor: "#ebebeb",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
// iOS shadow
|
||||
shadowColor: "#000",
|
||||
shadowOffset: { width: 0, height: 0 },
|
||||
shadowOpacity: 0,
|
||||
shadowRadius: 0,
|
||||
// Android shadow (elevation)
|
||||
elevation: 0,
|
||||
}}
|
||||
centerV
|
||||
>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
navigation.navigate("calendar");
|
||||
}}
|
||||
>
|
||||
<View
|
||||
centerV
|
||||
centerH
|
||||
height={54}
|
||||
paddingH-15
|
||||
style={ pageIndex == 1 || pageIndex == 0 ? styles.switchBtnActive : styles.switchBtn}
|
||||
>
|
||||
<Text color={pageIndex == 1 || pageIndex == 0 ? "white" : "black"} style={styles.switchTxt}>
|
||||
Calendar
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
const newIndex = navigationState.index === 6 ? 1 : 0;
|
||||
if (selectedIndex !== newIndex) {
|
||||
setSelectedIndex(newIndex);
|
||||
}
|
||||
isNavigating.current = false;
|
||||
}, [navigationState.index]);
|
||||
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
navigation.navigate("todos");
|
||||
}}
|
||||
>
|
||||
<View
|
||||
centerV
|
||||
centerH
|
||||
height={54}
|
||||
paddingH-15
|
||||
style={pageIndex == 6 ? styles.switchBtnActive : styles.switchBtn}
|
||||
>
|
||||
<Text color={pageIndex == 6 ? "white" : "black"} style={styles.switchTxt}>
|
||||
Chores
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
const handleSegmentChange = useCallback(
|
||||
(index: number) => {
|
||||
if (isNavigating.current) return;
|
||||
if (index === selectedIndex) return;
|
||||
|
||||
isNavigating.current = true;
|
||||
setSelectedIndex(index);
|
||||
|
||||
// Delay navigation slightly to allow the segment control to update
|
||||
requestAnimationFrame(() => {
|
||||
navigation.navigate(index === 0 ? "calendar" : "todos");
|
||||
});
|
||||
console.log(selectedIndex)
|
||||
},
|
||||
[navigation, selectedIndex]
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<SegmentedControl
|
||||
segments={[
|
||||
{ label: "Calendar", segmentLabelStyle: styles.labelStyle },
|
||||
{ label: "To Do's", segmentLabelStyle: styles.labelStyle },
|
||||
]}
|
||||
containerStyle={styles.segmentContainer}
|
||||
style={styles.segment}
|
||||
backgroundColor="#ebebeb"
|
||||
inactiveColor="black"
|
||||
activeColor="white"
|
||||
activeBackgroundColor="#ea156c"
|
||||
outlineColor="white"
|
||||
outlineWidth={3}
|
||||
onChangeIndex={handleSegmentChange}
|
||||
initialIndex={selectedIndex}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
});
|
||||
export default ViewSwitch;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
switchBtnActive: {
|
||||
backgroundColor: "#ea156c",
|
||||
borderRadius: 50,
|
||||
width: 110,
|
||||
},
|
||||
switchBtn: {
|
||||
container: {
|
||||
borderRadius: 30,
|
||||
backgroundColor: "#ebebeb",
|
||||
borderRadius: 50,
|
||||
width: 110,
|
||||
shadowColor: "#000",
|
||||
shadowOffset: { width: 0, height: 0 },
|
||||
shadowOpacity: 0,
|
||||
shadowRadius: 0,
|
||||
elevation: 0,
|
||||
},
|
||||
switchTxt: {
|
||||
segmentContainer: {
|
||||
height: 44,
|
||||
width: 220,
|
||||
},
|
||||
segment: {
|
||||
borderRadius: 50,
|
||||
borderWidth: 0,
|
||||
height: 44,
|
||||
},
|
||||
labelStyle: {
|
||||
fontSize: 16,
|
||||
fontFamily: "Manrope_600SemiBold",
|
||||
},
|
||||
|
||||
@ -21,7 +21,9 @@ const TabletCalendarPage = () => {
|
||||
|
||||
return (
|
||||
<TabletContainer>
|
||||
<InnerCalendar />
|
||||
<View flexG paddingB-25>
|
||||
<InnerCalendar />
|
||||
</View>
|
||||
</TabletContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { View, Text, ViewProps } from "react-native-ui-lib";
|
||||
import React, { ReactNode } from "react";
|
||||
import { Dimensions, StyleSheet } from "react-native";
|
||||
import React, { ReactNode, useEffect, useState } from "react";
|
||||
import { Dimensions, StyleSheet, useWindowDimensions } from "react-native";
|
||||
import UsersList from "./UsersList";
|
||||
import { ScrollView } from "react-native-gesture-handler";
|
||||
|
||||
@ -8,12 +8,52 @@ interface TabletContainerProps extends ViewProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
const { width, height } = Dimensions.get("window");
|
||||
|
||||
const TabletContainer: React.FC<TabletContainerProps> = ({
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
const window = useWindowDimensions();
|
||||
const [containerWidth, setContainerWidth] = useState(Dimensions.get('window').width);
|
||||
const [containerHeight, setContainerHeight] = useState(Dimensions.get('window').height);
|
||||
|
||||
// Update dimensions on mount and when window size changes
|
||||
useEffect(() => {
|
||||
const updateDimensions = () => {
|
||||
setContainerWidth(window.width);
|
||||
setContainerHeight(window.height);
|
||||
};
|
||||
|
||||
updateDimensions();
|
||||
|
||||
// Force a second update after a brief delay to handle any initial rendering issues
|
||||
const timer = setTimeout(updateDimensions, 100);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [window.width, window.height]);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: "white",
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
borderTopColor: "#a9a9a9",
|
||||
width: containerWidth,
|
||||
borderTopWidth: 1,
|
||||
},
|
||||
calendarContainer: {
|
||||
backgroundColor: "white",
|
||||
height: containerHeight,
|
||||
width: containerWidth * 0.89,
|
||||
},
|
||||
profilesContainer: {
|
||||
width: containerWidth * 0.11,
|
||||
height: containerHeight,
|
||||
borderLeftWidth: 1,
|
||||
borderLeftColor: "#a9a9a9",
|
||||
backgroundColor: "white",
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View row>
|
||||
@ -28,27 +68,4 @@ const TabletContainer: React.FC<TabletContainerProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: "white",
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
borderTopColor: "#a9a9a9",
|
||||
width: '80%',
|
||||
borderTopWidth: 1,
|
||||
},
|
||||
calendarContainer: {
|
||||
backgroundColor: "white",
|
||||
height: height,
|
||||
width: width * 0.89,
|
||||
},
|
||||
profilesContainer: {
|
||||
width: width * 0.11,
|
||||
height: height,
|
||||
borderLeftWidth: 1,
|
||||
borderLeftColor: "#a9a9a9",
|
||||
backgroundColor: "white",
|
||||
},
|
||||
});
|
||||
|
||||
export default TabletContainer;
|
||||
export default TabletContainer;
|
||||
@ -2,38 +2,19 @@ import React from "react";
|
||||
import { View } from "react-native-ui-lib";
|
||||
import HeaderTemplate from "@/components/shared/HeaderTemplate";
|
||||
import { InnerCalendar } from "@/components/pages/calendar/InnerCalendar";
|
||||
import { useSetAtom } from "jotai";
|
||||
import { refreshEnabledAtom } from "./atoms";
|
||||
|
||||
export default function CalendarPage() {
|
||||
const setRefreshEnabled = useSetAtom(refreshEnabledAtom);
|
||||
|
||||
const disableRefreshControl = () => setRefreshEnabled(false);
|
||||
const enableRefreshControl = () => setRefreshEnabled(true);
|
||||
return (
|
||||
<View
|
||||
style={{ flex: 1, height: "100%", padding: 10 }}
|
||||
paddingH-22
|
||||
paddingT-0
|
||||
>
|
||||
<View
|
||||
onStartShouldSetResponder={() => {
|
||||
enableRefreshControl();
|
||||
console.log("yeah");
|
||||
return true;
|
||||
}}
|
||||
onResponderRelease={() => {
|
||||
disableRefreshControl();
|
||||
console.log("sure");
|
||||
console.log(refreshEnabledAtom)
|
||||
}}
|
||||
>
|
||||
<HeaderTemplate
|
||||
message={"Let's get your week started !"}
|
||||
isWelcome
|
||||
isCalendar={true}
|
||||
/>
|
||||
</View>
|
||||
<HeaderTemplate
|
||||
message={"Let's get your week started !"}
|
||||
isWelcome
|
||||
isCalendar={true}
|
||||
/>
|
||||
<InnerCalendar />
|
||||
</View>
|
||||
);
|
||||
|
||||
@ -17,9 +17,9 @@ const DrawerButton = (props: IDrawerButtonProps) => {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
iconContainer: {
|
||||
width: "70%",
|
||||
width: isTablet ? '50%' : "70%",
|
||||
aspectRatio: 1,
|
||||
borderRadius: 50,
|
||||
borderRadius: 100,
|
||||
},
|
||||
labelStyle: { fontSize: 15, fontFamily: "Poppins_400Regular" },
|
||||
});
|
||||
@ -42,7 +42,7 @@ const DrawerButton = (props: IDrawerButtonProps) => {
|
||||
</View>
|
||||
)}
|
||||
style={{
|
||||
aspectRatio: 1,
|
||||
aspectRatio: isTablet ? 1.2 : 1,
|
||||
borderRadius: 18.55,
|
||||
marginBottom: 12,
|
||||
flexDirection: "column",
|
||||
|
||||
Reference in New Issue
Block a user