mirror of
https://github.com/urosran/cally.git
synced 2025-11-26 00:24:53 +00:00
Calendar page refactor
This commit is contained in:
@ -1,14 +1,11 @@
|
||||
import React from "react";
|
||||
import { CalendarProvider } from "@/contexts/CalendarContext"; // Import the new CalendarPage component
|
||||
import CalendarPage from "@/components/pages/calendar/CalendarPage";
|
||||
import { SettingsContextProvider } from "@/contexts/SettingsContext";
|
||||
import {SettingsContextProvider} from "@/contexts/SettingsContext";
|
||||
|
||||
export default function Screen() {
|
||||
return (
|
||||
<SettingsContextProvider>
|
||||
<CalendarProvider>
|
||||
<CalendarPage />
|
||||
</CalendarProvider>
|
||||
<CalendarPage/>
|
||||
</SettingsContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { DefaultTheme, ThemeProvider } from "@react-navigation/native";
|
||||
import React, {useEffect} from "react";
|
||||
import {DefaultTheme, ThemeProvider} from "@react-navigation/native";
|
||||
import {
|
||||
useFonts,
|
||||
Manrope_200ExtraLight,
|
||||
Manrope_300Light,
|
||||
Manrope_400Regular,
|
||||
@ -9,21 +8,22 @@ import {
|
||||
Manrope_600SemiBold,
|
||||
Manrope_700Bold,
|
||||
Manrope_800ExtraBold,
|
||||
useFonts,
|
||||
} from "@expo-google-fonts/manrope";
|
||||
import {
|
||||
PlusJakartaSans_200ExtraLight,
|
||||
PlusJakartaSans_300Light,
|
||||
PlusJakartaSans_400Regular,
|
||||
PlusJakartaSans_500Medium,
|
||||
PlusJakartaSans_600SemiBold,
|
||||
PlusJakartaSans_700Bold,
|
||||
PlusJakartaSans_800ExtraBold,
|
||||
PlusJakartaSans_200ExtraLight_Italic,
|
||||
PlusJakartaSans_300Light,
|
||||
PlusJakartaSans_300Light_Italic,
|
||||
PlusJakartaSans_400Regular,
|
||||
PlusJakartaSans_400Regular_Italic,
|
||||
PlusJakartaSans_500Medium,
|
||||
PlusJakartaSans_500Medium_Italic,
|
||||
PlusJakartaSans_600SemiBold,
|
||||
PlusJakartaSans_600SemiBold_Italic,
|
||||
PlusJakartaSans_700Bold,
|
||||
PlusJakartaSans_700Bold_Italic,
|
||||
PlusJakartaSans_800ExtraBold,
|
||||
PlusJakartaSans_800ExtraBold_Italic,
|
||||
} from "@expo-google-fonts/plus-jakarta-sans";
|
||||
import {
|
||||
@ -46,29 +46,21 @@ import {
|
||||
Poppins_900Black,
|
||||
Poppins_900Black_Italic,
|
||||
} from "@expo-google-fonts/poppins";
|
||||
import { Stack } from "expo-router";
|
||||
import {Stack} from "expo-router";
|
||||
import * as SplashScreen from "expo-splash-screen";
|
||||
import "react-native-reanimated";
|
||||
import { AuthContextProvider } from "@/contexts/AuthContext";
|
||||
import { QueryClient, QueryClientProvider } from "react-query";
|
||||
import {
|
||||
ThemeManager,
|
||||
Typography,
|
||||
Toast,
|
||||
TextProps,
|
||||
} from "react-native-ui-lib";
|
||||
import functions from "@react-native-firebase/functions";
|
||||
import auth from "@react-native-firebase/auth";
|
||||
import firestore from "@react-native-firebase/firestore";
|
||||
import {AuthContextProvider} from "@/contexts/AuthContext";
|
||||
import {QueryClient, QueryClientProvider} from "react-query";
|
||||
import {TextProps, ThemeManager, Toast, Typography,} from "react-native-ui-lib";
|
||||
|
||||
SplashScreen.preventAutoHideAsync();
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
if (__DEV__) {
|
||||
functions().useEmulator("localhost", 5001);
|
||||
firestore().useEmulator("localhost", 5471);
|
||||
auth().useEmulator("http://localhost:9099");
|
||||
// functions().useEmulator("localhost", 5001);
|
||||
// firestore().useEmulator("localhost", 5471);
|
||||
// auth().useEmulator("http://localhost:9099");
|
||||
}
|
||||
|
||||
type TextStyleBase =
|
||||
@ -160,7 +152,7 @@ const getManropeFontStyle = (style: TextStyle): FontStyle => {
|
||||
fontSize = 16;
|
||||
}
|
||||
|
||||
return { fontFamily, fontSize };
|
||||
return {fontFamily, fontSize};
|
||||
};
|
||||
|
||||
export default function RootLayout() {
|
||||
@ -236,7 +228,7 @@ export default function RootLayout() {
|
||||
|
||||
ThemeManager.setComponentTheme(
|
||||
"Text",
|
||||
(props: ExtendedTextProps, context: unknown) => {
|
||||
(props: ExtendedTextProps) => {
|
||||
const textStyle = (
|
||||
Object.keys(props) as Array<keyof ExtendedTextProps>
|
||||
).find((key) => typographies[key as TextStyle]) as
|
||||
@ -263,11 +255,11 @@ export default function RootLayout() {
|
||||
<AuthContextProvider>
|
||||
<ThemeProvider value={DefaultTheme}>
|
||||
<Stack>
|
||||
<Stack.Screen name="(auth)" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="(unauth)" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="+not-found" />
|
||||
<Stack.Screen name="(auth)" options={{headerShown: false}}/>
|
||||
<Stack.Screen name="(unauth)" options={{headerShown: false}}/>
|
||||
<Stack.Screen name="+not-found"/>
|
||||
</Stack>
|
||||
<Toast />
|
||||
<Toast/>
|
||||
</ThemeProvider>
|
||||
</AuthContextProvider>
|
||||
</QueryClientProvider>
|
||||
|
||||
@ -1,38 +1,26 @@
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
AntDesign,
|
||||
Feather,
|
||||
MaterialCommunityIcons,
|
||||
MaterialIcons,
|
||||
} from "@expo/vector-icons";
|
||||
import {
|
||||
Button,
|
||||
ButtonSize,
|
||||
Card,
|
||||
Dialog,
|
||||
PanningProvider,
|
||||
Text,
|
||||
View,
|
||||
} from "react-native-ui-lib";
|
||||
import { StyleSheet, TouchableOpacity } from "react-native";
|
||||
import { ManuallyAddEventModal } from "@/components/pages/calendar/ManuallyAddEventModal";
|
||||
import React, {useState} from "react";
|
||||
import {MaterialIcons,} from "@expo/vector-icons";
|
||||
import {Button, Card, Dialog, PanningProvider, Text, View,} from "react-native-ui-lib";
|
||||
import {StyleSheet, TouchableOpacity} from "react-native";
|
||||
import AddChoreDialog from "../todos/AddChoreDialog";
|
||||
import { ToDosContextProvider } from "@/contexts/ToDosContext";
|
||||
import {ToDosContextProvider} from "@/contexts/ToDosContext";
|
||||
import UploadImageDialog from "./UploadImageDialog";
|
||||
import CameraIcon from "@/assets/svgs/CameraIcon";
|
||||
import CalendarIcon from "@/assets/svgs/CalendarIcon";
|
||||
import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
|
||||
import {useSetAtom} from "jotai";
|
||||
import {selectedNewEventDateAtom} from "@/components/pages/calendar/atoms";
|
||||
|
||||
export const AddEventDialog = () => {
|
||||
const [show, setShow] = useState(false);
|
||||
const [showManualInputModal, setShowManualInputModal] = useState(false);
|
||||
const [choreDialogVisible, setChoreDialogVisible] = useState<boolean>(false);
|
||||
const [showUploadDialog, setShowUploadDialog] = useState<boolean>(false);
|
||||
const setSelectedNewEndDate = useSetAtom(selectedNewEventDateAtom)
|
||||
|
||||
const handleOpenManualInputModal = () => {
|
||||
setShow(false);
|
||||
setTimeout(() => {
|
||||
setShowManualInputModal(true);
|
||||
setSelectedNewEndDate(new Date());
|
||||
}, 500);
|
||||
};
|
||||
|
||||
@ -62,8 +50,8 @@ export const AddEventDialog = () => {
|
||||
onPress={() => setShow(true)}
|
||||
>
|
||||
<View row centerV centerH>
|
||||
<MaterialIcons name="add" size={22} color={"white"} />
|
||||
<Text white style={{ fontSize: 16, fontFamily: 'Manrope_600SemiBold' }}>
|
||||
<MaterialIcons name="add" size={22} color={"white"}/>
|
||||
<Text white style={{fontSize: 16, fontFamily: 'Manrope_600SemiBold'}}>
|
||||
New
|
||||
</Text>
|
||||
</View>
|
||||
@ -81,7 +69,7 @@ export const AddEventDialog = () => {
|
||||
</Text>
|
||||
|
||||
<View
|
||||
style={{ marginTop: 20, alignItems: "center", width: "100%" }}
|
||||
style={{marginTop: 20, alignItems: "center", width: "100%"}}
|
||||
>
|
||||
<Button
|
||||
style={{
|
||||
@ -95,7 +83,7 @@ export const AddEventDialog = () => {
|
||||
labelStyle={styles.btnLabel}
|
||||
onPress={handleScanImageDialog}
|
||||
iconSource={() => (
|
||||
<CameraIcon color="white" style={styles.btnIcon} />
|
||||
<CameraIcon color="white" style={styles.btnIcon}/>
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -111,7 +99,7 @@ export const AddEventDialog = () => {
|
||||
labelStyle={styles.btnLabel}
|
||||
onPress={handleOpenManualInputModal}
|
||||
iconSource={() => (
|
||||
<CalendarIcon color={"white"} style={styles.btnIcon} />
|
||||
<CalendarIcon color={"white"} style={styles.btnIcon}/>
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -147,10 +135,6 @@ export const AddEventDialog = () => {
|
||||
isVisible={choreDialogVisible}
|
||||
setIsVisible={setChoreDialogVisible}
|
||||
/>
|
||||
<ManuallyAddEventModal
|
||||
show={showManualInputModal}
|
||||
close={() => setShowManualInputModal(false)}
|
||||
/>
|
||||
<UploadImageDialog
|
||||
show={showUploadDialog}
|
||||
setShow={setShowUploadDialog}
|
||||
@ -184,5 +168,5 @@ const styles = StyleSheet.create({
|
||||
fontSize: 15,
|
||||
fontFamily: "PlusJakartaSans_500Medium",
|
||||
},
|
||||
btnIcon: { marginRight: 10 },
|
||||
btnIcon: {marginRight: 10},
|
||||
});
|
||||
|
||||
102
components/pages/calendar/CalendarHeader.tsx
Normal file
102
components/pages/calendar/CalendarHeader.tsx
Normal file
@ -0,0 +1,102 @@
|
||||
import React, {memo} from 'react';
|
||||
import {Picker, PickerModes, SegmentedControl, Text, View} from "react-native-ui-lib";
|
||||
import {MaterialIcons} from "@expo/vector-icons";
|
||||
import {modeMap, months} from './constants';
|
||||
import {StyleSheet} from "react-native";
|
||||
import {useAtom} from "jotai";
|
||||
import {modeAtom, selectedDateAtom} from "@/components/pages/calendar/atoms";
|
||||
|
||||
|
||||
export const CalendarHeader = memo(() => {
|
||||
const [selectedDate, setSelectedDate] = useAtom(selectedDateAtom)
|
||||
const [mode, setMode] = useAtom(modeAtom)
|
||||
|
||||
const handleSegmentChange = (index: number) => {
|
||||
const selectedMode = modeMap.get(index);
|
||||
if (selectedMode) {
|
||||
setMode(selectedMode as "day" | "week" | "month");
|
||||
}
|
||||
};
|
||||
|
||||
const handleMonthChange = (month: string) => {
|
||||
const currentDay = selectedDate.getDate();
|
||||
const currentYear = selectedDate.getFullYear();
|
||||
|
||||
const newMonthIndex = months.indexOf(month);
|
||||
|
||||
const updatedDate = new Date(currentYear, newMonthIndex, currentDay);
|
||||
|
||||
setSelectedDate(updatedDate);
|
||||
};
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 8,
|
||||
borderRadius: 20,
|
||||
borderBottomLeftRadius: 0,
|
||||
borderBottomRightRadius: 0,
|
||||
backgroundColor: "white",
|
||||
marginBottom: 10,
|
||||
}}
|
||||
>
|
||||
<View row centerV gap-3>
|
||||
<Text style={{fontFamily: "Manrope_500Medium", fontSize: 17}}>
|
||||
{selectedDate.getFullYear()}
|
||||
</Text>
|
||||
<Picker
|
||||
value={months[selectedDate.getMonth()]}
|
||||
placeholder={"Select Month"}
|
||||
style={{fontFamily: "Manrope_500Medium", fontSize: 17}}
|
||||
mode={PickerModes.SINGLE}
|
||||
onChange={(itemValue) => handleMonthChange(itemValue as string)}
|
||||
trailingAccessory={<MaterialIcons name={"keyboard-arrow-down"}/>}
|
||||
topBarProps={{
|
||||
title: selectedDate.getFullYear().toString(),
|
||||
titleStyle: {fontFamily: "Manrope_500Medium", fontSize: 17},
|
||||
}}
|
||||
>
|
||||
{months.map((month) => (
|
||||
<Picker.Item key={month} label={month} value={month}/>
|
||||
))}
|
||||
</Picker>
|
||||
</View>
|
||||
|
||||
<View>
|
||||
<SegmentedControl
|
||||
segments={[{label: "D"}, {label: "W"}, {label: "M"}]}
|
||||
backgroundColor="#ececec"
|
||||
inactiveColor="#919191"
|
||||
activeBackgroundColor="#ea156c"
|
||||
activeColor="white"
|
||||
outlineColor="white"
|
||||
outlineWidth={3}
|
||||
segmentLabelStyle={styles.segmentslblStyle}
|
||||
onChangeIndex={handleSegmentChange}
|
||||
initialIndex={mode === "day" ? 0 : mode === "week" ? 1 : 2}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
});
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
segmentslblStyle: {
|
||||
fontSize: 12,
|
||||
fontFamily: "Manrope_600SemiBold",
|
||||
},
|
||||
calHeader: {
|
||||
borderWidth: 0,
|
||||
},
|
||||
dayModeHeader: {
|
||||
alignSelf: "flex-start",
|
||||
justifyContent: "space-between",
|
||||
alignContent: "center",
|
||||
width: 38,
|
||||
right: 42,
|
||||
},
|
||||
});
|
||||
@ -1,207 +1,20 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
import { LayoutChangeEvent, StyleSheet } from "react-native";
|
||||
import { Calendar } from "react-native-big-calendar";
|
||||
import {
|
||||
Picker,
|
||||
PickerModes,
|
||||
SegmentedControl,
|
||||
View,
|
||||
} from "react-native-ui-lib";
|
||||
import { MaterialIcons } from "@expo/vector-icons";
|
||||
import { AddEventDialog } from "@/components/pages/calendar/AddEventDialog";
|
||||
import React from "react";
|
||||
import {View,} from "react-native-ui-lib";
|
||||
import HeaderTemplate from "@/components/shared/HeaderTemplate";
|
||||
import CalendarViewSwitch from "@/components/pages/calendar/CalendarViewSwitch";
|
||||
import { ManuallyAddEventModal } from "@/components/pages/calendar/ManuallyAddEventModal";
|
||||
import { CalendarEvent } from "@/contexts/CalendarContext";
|
||||
import { useSettingsContext } from "@/contexts/SettingsContext";
|
||||
import EditEventDialog from "./EditEventDialog";
|
||||
import { useGetEvents } from "@/hooks/firebase/useGetEvents";
|
||||
import { Text } from "react-native-ui-lib";
|
||||
|
||||
const modeMap = new Map([
|
||||
[0, "day"],
|
||||
[1, "week"],
|
||||
[2, "month"],
|
||||
]);
|
||||
|
||||
const months = [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December",
|
||||
];
|
||||
import {InnerCalendar} from "@/components/pages/calendar/InnerCalendar";
|
||||
|
||||
export default function CalendarPage() {
|
||||
const { calendarColor } = useSettingsContext();
|
||||
const [editVisible, setEditVisible] = useState<boolean>(false);
|
||||
const [eventForEdit, setEventForEdit] = useState<CalendarEvent>();
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
segmentslblStyle: {
|
||||
fontSize: 12,
|
||||
fontFamily: "Manrope_600SemiBold",
|
||||
},
|
||||
calHeader: {
|
||||
borderWidth: 0,
|
||||
},
|
||||
dayModeHeader: {
|
||||
alignSelf: "flex-start",
|
||||
justifyContent: "space-between",
|
||||
alignContent: "center",
|
||||
width: 38,
|
||||
right: 42,
|
||||
},
|
||||
});
|
||||
|
||||
const [isFamilyView, setIsFamilyView] = useState<boolean>(false);
|
||||
const [calendarHeight, setCalendarHeight] = useState(0);
|
||||
const [mode, setMode] = useState<"week" | "month" | "day">("week");
|
||||
const [selectedDate, setSelectedDate] = useState<Date>(new Date());
|
||||
const [selectedNewEventDate, setSelectedNewEndDate] = useState<
|
||||
Date | undefined
|
||||
>(undefined);
|
||||
|
||||
const calendarContainerRef = useRef(null);
|
||||
const { data: events } = useGetEvents(isFamilyView);
|
||||
|
||||
const onLayout = (event: LayoutChangeEvent) => {
|
||||
const { height } = event.nativeEvent.layout;
|
||||
setCalendarHeight(height);
|
||||
};
|
||||
|
||||
const handleSegmentChange = (index: number) => {
|
||||
const selectedMode = modeMap.get(index);
|
||||
if (selectedMode) {
|
||||
setMode(selectedMode as "day" | "week" | "month");
|
||||
}
|
||||
};
|
||||
|
||||
const handleMonthChange = (month: string) => {
|
||||
const currentDay = selectedDate.getDate();
|
||||
const currentYear = selectedDate.getFullYear();
|
||||
|
||||
const newMonthIndex = months.indexOf(month);
|
||||
|
||||
const updatedDate = new Date(currentYear, newMonthIndex, currentDay);
|
||||
|
||||
setSelectedDate(updatedDate);
|
||||
};
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{ flex: 1, height: "100%", padding: 10 }}
|
||||
style={{flex: 1, height: "100%", padding: 10}}
|
||||
paddingH-22
|
||||
paddingT-0
|
||||
>
|
||||
<HeaderTemplate
|
||||
message={"Let's get your week started!"}
|
||||
isWelcome={true}
|
||||
/>
|
||||
|
||||
<View
|
||||
style={{ flex: 1, backgroundColor: "#fff", borderRadius: 30 }}
|
||||
ref={calendarContainerRef}
|
||||
onLayout={onLayout}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 8,
|
||||
borderRadius: 20,
|
||||
borderBottomLeftRadius: 0,
|
||||
borderBottomRightRadius: 0,
|
||||
backgroundColor: "white",
|
||||
marginBottom: 10,
|
||||
}}
|
||||
>
|
||||
<View row centerV gap-3>
|
||||
<Text style={{ fontFamily: "Manrope_500Medium", fontSize: 17 }}>
|
||||
{selectedDate.getFullYear()}
|
||||
</Text>
|
||||
<Picker
|
||||
value={months[selectedDate.getMonth()]} // Get the month from the date
|
||||
placeholder={"Select Month"}
|
||||
style={{ fontFamily: "Manrope_500Medium", fontSize: 17 }}
|
||||
mode={PickerModes.SINGLE}
|
||||
onChange={(itemValue) => handleMonthChange(itemValue as string)}
|
||||
trailingAccessory={<MaterialIcons name={"keyboard-arrow-down"} />}
|
||||
topBarProps={{
|
||||
title: selectedDate.getFullYear().toString(),
|
||||
titleStyle: { fontFamily: "Manrope_500Medium", fontSize: 17 },
|
||||
}}
|
||||
>
|
||||
{months.map((month) => (
|
||||
<Picker.Item key={month} label={month} value={month} />
|
||||
))}
|
||||
</Picker>
|
||||
</View>
|
||||
|
||||
<View>
|
||||
<SegmentedControl
|
||||
segments={[{ label: "D" }, { label: "W" }, { label: "M" }]}
|
||||
backgroundColor="#ececec"
|
||||
inactiveColor="#919191"
|
||||
activeBackgroundColor="#ea156c"
|
||||
activeColor="white"
|
||||
outlineColor="white"
|
||||
outlineWidth={3}
|
||||
segmentLabelStyle={styles.segmentslblStyle}
|
||||
onChangeIndex={handleSegmentChange}
|
||||
initialIndex={mode === "day" ? 0 : mode === "week" ? 1 : 2}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{calendarHeight > 0 && (
|
||||
<Calendar
|
||||
bodyContainerStyle={styles.calHeader}
|
||||
mode={mode}
|
||||
events={isFamilyView ? events ?? [] : events ?? []}
|
||||
eventCellStyle={(event) => ({ backgroundColor: event.eventColor })}
|
||||
onPressEvent={(event) => {
|
||||
setEditVisible(true);
|
||||
setEventForEdit(event);
|
||||
}}
|
||||
height={calendarHeight}
|
||||
activeDate={selectedDate}
|
||||
date={selectedDate}
|
||||
onPressCell={setSelectedNewEndDate}
|
||||
headerContentStyle={mode === "day" ? styles.dayModeHeader : {}}
|
||||
onSwipeEnd={(date) => {
|
||||
setSelectedDate(date);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<CalendarViewSwitch viewSwitch={setIsFamilyView} />
|
||||
<AddEventDialog />
|
||||
{eventForEdit && (
|
||||
<EditEventDialog
|
||||
isVisible={editVisible}
|
||||
setIsVisible={() => {
|
||||
setEditVisible(!editVisible);
|
||||
}}
|
||||
event={eventForEdit}
|
||||
/>
|
||||
)}
|
||||
|
||||
<ManuallyAddEventModal
|
||||
key={`${selectedNewEventDate}`}
|
||||
initialDate={selectedNewEventDate}
|
||||
show={!!selectedNewEventDate}
|
||||
close={() => setSelectedNewEndDate(undefined)}
|
||||
isWelcome
|
||||
/>
|
||||
<InnerCalendar/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { View, Text, Button, TouchableOpacity } from "react-native-ui-lib";
|
||||
import React, { useState } from "react";
|
||||
import { MaterialIcons } from "@expo/vector-icons";
|
||||
import { StyleSheet } from "react-native";
|
||||
import {Text, TouchableOpacity, View} from "react-native-ui-lib";
|
||||
import React, {useState} from "react";
|
||||
import {StyleSheet} from "react-native";
|
||||
import {useSetAtom} from "jotai";
|
||||
import {isFamilyViewAtom} from "@/components/pages/calendar/atoms";
|
||||
|
||||
interface ICalendarViewProps {
|
||||
viewSwitch: (value: boolean) => void;
|
||||
}
|
||||
const CalendarViewSwitch = (calendarViewProps: ICalendarViewProps) => {
|
||||
|
||||
const CalendarViewSwitch = () => {
|
||||
const [calView, setCalView] = useState<boolean>(false);
|
||||
const viewSwitch = useSetAtom(isFamilyViewAtom)
|
||||
|
||||
return (
|
||||
<View
|
||||
@ -23,7 +23,7 @@ const CalendarViewSwitch = (calendarViewProps: ICalendarViewProps) => {
|
||||
justifyContent: "center",
|
||||
// iOS shadow
|
||||
shadowColor: "#000",
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOffset: {width: 0, height: 2},
|
||||
shadowOpacity: 0.25,
|
||||
shadowRadius: 3.84,
|
||||
// Android shadow (elevation)
|
||||
@ -34,7 +34,7 @@ const CalendarViewSwitch = (calendarViewProps: ICalendarViewProps) => {
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
setCalView(true);
|
||||
calendarViewProps.viewSwitch(true);
|
||||
viewSwitch(true);
|
||||
}}
|
||||
>
|
||||
<View
|
||||
@ -53,7 +53,7 @@ const CalendarViewSwitch = (calendarViewProps: ICalendarViewProps) => {
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
setCalView(false);
|
||||
calendarViewProps.viewSwitch(false);
|
||||
viewSwitch(false);
|
||||
}}
|
||||
>
|
||||
<View
|
||||
@ -83,7 +83,7 @@ const styles = StyleSheet.create({
|
||||
backgroundColor: "white",
|
||||
borderRadius: 50,
|
||||
},
|
||||
switchTxt:{
|
||||
switchTxt: {
|
||||
fontSize: 16,
|
||||
fontFamily: 'Manrope_600SemiBold'
|
||||
}
|
||||
|
||||
@ -1,42 +1,31 @@
|
||||
import { View, Text, Button, Switch } from "react-native-ui-lib";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Feather, AntDesign, Ionicons } from "@expo/vector-icons";
|
||||
import {
|
||||
Dialog,
|
||||
TextField,
|
||||
DateTimePicker,
|
||||
Picker,
|
||||
ButtonSize,
|
||||
} from "react-native-ui-lib";
|
||||
import { PanningDirectionsEnum } from "react-native-ui-lib/src/incubator/panView";
|
||||
import { StyleSheet } from "react-native";
|
||||
import {Button, ButtonSize, DateTimePicker, Dialog, Switch, Text, TextField, View} from "react-native-ui-lib";
|
||||
import React from "react";
|
||||
import {AntDesign, Feather, Ionicons} from "@expo/vector-icons";
|
||||
import {PanningDirectionsEnum} from "react-native-ui-lib/src/incubator/panView";
|
||||
import {StyleSheet} from "react-native";
|
||||
import DropModalIcon from "@/assets/svgs/DropModalIcon";
|
||||
import { CalendarEvent } from "@/contexts/CalendarContext";
|
||||
import ClockIcon from "@/assets/svgs/ClockIcon";
|
||||
import LockIcon from "@/assets/svgs/LockIcon";
|
||||
import MenuIcon from "@/assets/svgs/MenuIcon";
|
||||
import { useUpdateEvent } from "@/hooks/firebase/useUpdateEvent";
|
||||
import {useUpdateEvent} from "@/hooks/firebase/useUpdateEvent";
|
||||
import {editVisibleAtom, eventForEditAtom} from "@/components/pages/calendar/atoms";
|
||||
import {useAtom} from "jotai";
|
||||
|
||||
interface IEditEventDialog {
|
||||
event: CalendarEvent;
|
||||
isVisible: boolean;
|
||||
setIsVisible: (value: boolean) => void;
|
||||
}
|
||||
const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
const [event, setEvent] = useState<CalendarEvent>(editEventProps.event);
|
||||
|
||||
const { mutateAsync: updateEvent } = useUpdateEvent();
|
||||
const EditEventDialog = () => {
|
||||
const [isVisible, setIsVisible] = useAtom(editVisibleAtom)
|
||||
const [event, setEvent] = useAtom(eventForEditAtom)
|
||||
|
||||
useEffect(() => {
|
||||
setEvent(editEventProps.event);
|
||||
}, [editEventProps.isVisible]);
|
||||
const {mutateAsync: updateEvent} = useUpdateEvent();
|
||||
|
||||
if (!event) return null
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
bottom={true}
|
||||
height={"90%"}
|
||||
panDirection={PanningDirectionsEnum.DOWN}
|
||||
onDismiss={() => editEventProps.setIsVisible(false)}
|
||||
onDismiss={() => setIsVisible(false)}
|
||||
containerStyle={{
|
||||
borderRadius: 10,
|
||||
backgroundColor: "white",
|
||||
@ -46,7 +35,7 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
paddingTop: 4,
|
||||
margin: 0,
|
||||
}}
|
||||
visible={editEventProps.isVisible}
|
||||
visible={isVisible}
|
||||
>
|
||||
<View row spread>
|
||||
<Button
|
||||
@ -54,13 +43,13 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
style={styles.topBtn}
|
||||
label="Cancel"
|
||||
onPress={() => {
|
||||
editEventProps.setIsVisible(false);
|
||||
setIsVisible(false);
|
||||
}}
|
||||
/>
|
||||
<View marginT-12>
|
||||
<DropModalIcon
|
||||
onPress={() => {
|
||||
editEventProps.setIsVisible(false);
|
||||
setIsVisible(false);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
@ -71,7 +60,7 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
onPress={() => {
|
||||
try {
|
||||
if (event.id) {
|
||||
updateEvent(event).then(() => editEventProps.setIsVisible(false));
|
||||
updateEvent(event).then(() => setIsVisible(false));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@ -85,7 +74,7 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
value={event.title}
|
||||
onChangeText={(text) => {
|
||||
setEvent((prevEvent) => ({
|
||||
...prevEvent,
|
||||
...prevEvent!,
|
||||
title: text,
|
||||
}));
|
||||
}}
|
||||
@ -94,11 +83,11 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
marginT-15
|
||||
marginL-30
|
||||
/>
|
||||
<View style={styles.divider} marginT-8 />
|
||||
<View style={styles.divider} marginT-8/>
|
||||
|
||||
<View row spread marginB-10 marginL-30 centerV>
|
||||
<View row>
|
||||
<AntDesign name="clockcircleo" size={24} color="#919191" />
|
||||
<AntDesign name="clockcircleo" size={24} color="#919191"/>
|
||||
<Text text70 marginL-10>
|
||||
All day
|
||||
</Text>
|
||||
@ -110,7 +99,7 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
marginL-10
|
||||
value={event.allDay}
|
||||
onValueChange={(value) =>
|
||||
setEvent((prev) => ({ ...prev, allDay: value }))
|
||||
setEvent((prev) => ({...prev!, allDay: value}))
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
@ -118,14 +107,14 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
<View marginL-30 centerV>
|
||||
<View row marginB-10 spread>
|
||||
<View row centerV>
|
||||
<Feather name="calendar" size={25} color="#919191" />
|
||||
<Feather name="calendar" size={25} color="#919191"/>
|
||||
<DateTimePicker
|
||||
value={event.start}
|
||||
text70
|
||||
marginL-8
|
||||
maximumDate={event.end}
|
||||
onChange={(date) => {
|
||||
setEvent((prev) => ({ ...prev, start: date }));
|
||||
setEvent((prev) => ({...prev!, start: date}));
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
@ -133,11 +122,12 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
text70
|
||||
value={event.start}
|
||||
onChange={(date) => {
|
||||
setEvent((prev) => ({ ...prev, start: date }));
|
||||
setEvent((prev) => ({...prev!, start: date}));
|
||||
}}
|
||||
maximumDate={event.end}
|
||||
dateTimeFormatter={(date, mode) => date.toLocaleTimeString("en-us",
|
||||
{ hour: "numeric",
|
||||
dateTimeFormatter={(date) => date.toLocaleTimeString("en-us",
|
||||
{
|
||||
hour: "numeric",
|
||||
minute: "numeric"
|
||||
})}
|
||||
mode="time"
|
||||
@ -148,14 +138,14 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
{!event.allDay && (
|
||||
<View row marginB-10 spread>
|
||||
<View row centerV>
|
||||
<Feather name="calendar" size={25} color="#919191" />
|
||||
<Feather name="calendar" size={25} color="#919191"/>
|
||||
<DateTimePicker
|
||||
value={event.end}
|
||||
minimumDate={event.start}
|
||||
text70
|
||||
marginL-8
|
||||
onChange={(date) => {
|
||||
setEvent((prev) => ({ ...prev, end: date }));
|
||||
setEvent((prev) => ({...prev!, end: date}));
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
@ -164,10 +154,11 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
value={event.end}
|
||||
minimumDate={event.start}
|
||||
onChange={(date) => {
|
||||
setEvent((prev) => ({ ...prev, end: date }));
|
||||
setEvent((prev) => ({...prev!, end: date}));
|
||||
}}
|
||||
dateTimeFormatter={(date, mode) => date.toLocaleTimeString("en-us",
|
||||
{ hour: "numeric",
|
||||
dateTimeFormatter={(date) => date.toLocaleTimeString("en-us",
|
||||
{
|
||||
hour: "numeric",
|
||||
minute: "numeric"
|
||||
})}
|
||||
mode="time"
|
||||
@ -176,10 +167,10 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.divider} />
|
||||
<View style={styles.divider}/>
|
||||
|
||||
<View marginH-30 marginB-10 row centerV>
|
||||
<Ionicons name="person-circle-outline" size={28} color="#919191" />
|
||||
<Ionicons name="person-circle-outline" size={28} color="#919191"/>
|
||||
<Text text70R marginL-10>
|
||||
Assignees
|
||||
</Text>
|
||||
@ -187,7 +178,7 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
size={ButtonSize.small}
|
||||
paddingH-8
|
||||
iconSource={() => (
|
||||
<Ionicons name="add-outline" size={20} color="#ea156c" />
|
||||
<Ionicons name="add-outline" size={20} color="#ea156c"/>
|
||||
)}
|
||||
style={{
|
||||
marginLeft: "auto",
|
||||
@ -220,10 +211,10 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.divider} />
|
||||
<View style={styles.divider}/>
|
||||
<View marginH-30 marginB-0 row spread centerV>
|
||||
<View row centerV>
|
||||
<ClockIcon />
|
||||
<ClockIcon/>
|
||||
<Text text70 marginL-10>
|
||||
Reminder
|
||||
</Text>
|
||||
@ -233,7 +224,7 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
size={ButtonSize.small}
|
||||
paddingH-8
|
||||
iconSource={() => (
|
||||
<Ionicons name="add-outline" size={20} color="#ea156c" />
|
||||
<Ionicons name="add-outline" size={20} color="#ea156c"/>
|
||||
)}
|
||||
style={{
|
||||
marginLeft: "auto",
|
||||
@ -247,10 +238,10 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.divider} />
|
||||
<View style={styles.divider}/>
|
||||
<View marginH-30 marginB-0 row spread centerV>
|
||||
<View row>
|
||||
<LockIcon />
|
||||
<LockIcon/>
|
||||
<Text text70 marginL-10>
|
||||
Mark as Private
|
||||
</Text>
|
||||
@ -262,15 +253,15 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
marginL-10
|
||||
value={event.private}
|
||||
onValueChange={(value) =>
|
||||
setEvent((prev) => ({ ...prev, private: value }))
|
||||
setEvent((prev) => ({...prev!, private: value}))
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.divider} />
|
||||
<View style={styles.divider}/>
|
||||
<View marginH-30 marginB-0 row spread centerV>
|
||||
<View row centerV>
|
||||
<MenuIcon />
|
||||
<MenuIcon/>
|
||||
<Text text70 marginL-10>
|
||||
Add Details
|
||||
</Text>
|
||||
@ -284,7 +275,7 @@ const EditEventDialog = (editEventProps: IEditEventDialog) => {
|
||||
export default EditEventDialog;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
divider: { height: 1, backgroundColor: "#e4e4e4", marginVertical: 15 },
|
||||
divider: {height: 1, backgroundColor: "#e4e4e4", marginVertical: 15},
|
||||
gradient: {
|
||||
height: "25%",
|
||||
position: "absolute",
|
||||
|
||||
63
components/pages/calendar/EventCalendar.tsx
Normal file
63
components/pages/calendar/EventCalendar.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
import React, {memo} from 'react';
|
||||
import {Calendar} from "react-native-big-calendar";
|
||||
import {StyleSheet} from "react-native";
|
||||
import {useGetEvents} from "@/hooks/firebase/useGetEvents";
|
||||
import {useAtom, useAtomValue, useSetAtom} from "jotai";
|
||||
import {
|
||||
editVisibleAtom,
|
||||
eventForEditAtom,
|
||||
modeAtom,
|
||||
selectedDateAtom,
|
||||
selectedNewEventDateAtom
|
||||
} from "@/components/pages/calendar/atoms";
|
||||
|
||||
interface EventCalendarProps {
|
||||
calendarHeight: number;
|
||||
}
|
||||
|
||||
export const EventCalendar: React.FC<EventCalendarProps> = memo(({calendarHeight}) => {
|
||||
const {data: events} = useGetEvents();
|
||||
const [selectedDate, setSelectedDate] = useAtom(selectedDateAtom)
|
||||
const mode = useAtomValue(modeAtom)
|
||||
const setEditVisible = useSetAtom(editVisibleAtom)
|
||||
const setEventForEdit = useSetAtom(eventForEditAtom)
|
||||
const setSelectedNewEndDate = useSetAtom(selectedNewEventDateAtom)
|
||||
|
||||
return (
|
||||
<Calendar
|
||||
bodyContainerStyle={styles.calHeader}
|
||||
mode={mode}
|
||||
events={events ?? []}
|
||||
eventCellStyle={(event) => ({backgroundColor: event.eventColor})}
|
||||
onPressEvent={(event) => {
|
||||
setEditVisible(true);
|
||||
setEventForEdit(event);
|
||||
}}
|
||||
height={calendarHeight}
|
||||
activeDate={selectedDate}
|
||||
date={selectedDate}
|
||||
onPressCell={setSelectedNewEndDate}
|
||||
headerContentStyle={mode === "day" ? styles.dayModeHeader : {}}
|
||||
onSwipeEnd={(date) => {
|
||||
setSelectedDate(date);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
segmentslblStyle: {
|
||||
fontSize: 12,
|
||||
fontFamily: "Manrope_600SemiBold",
|
||||
},
|
||||
calHeader: {
|
||||
borderWidth: 0,
|
||||
},
|
||||
dayModeHeader: {
|
||||
alignSelf: "flex-start",
|
||||
justifyContent: "space-between",
|
||||
alignContent: "center",
|
||||
width: 38,
|
||||
right: 42,
|
||||
},
|
||||
});
|
||||
41
components/pages/calendar/InnerCalendar.tsx
Normal file
41
components/pages/calendar/InnerCalendar.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import {View} from "react-native-ui-lib";
|
||||
import React, {useRef, useState} from "react";
|
||||
import {LayoutChangeEvent} from "react-native";
|
||||
import CalendarViewSwitch from "@/components/pages/calendar/CalendarViewSwitch";
|
||||
import {AddEventDialog} from "@/components/pages/calendar/AddEventDialog";
|
||||
import EditEventDialog from "@/components/pages/calendar/EditEventDialog";
|
||||
import {ManuallyAddEventModal} from "@/components/pages/calendar/ManuallyAddEventModal";
|
||||
import {CalendarHeader} from "@/components/pages/calendar/CalendarHeader";
|
||||
import {EventCalendar} from "@/components/pages/calendar/EventCalendar";
|
||||
|
||||
export const InnerCalendar = () => {
|
||||
const [calendarHeight, setCalendarHeight] = useState(0);
|
||||
const calendarContainerRef = useRef(null);
|
||||
|
||||
const onLayout = (event: LayoutChangeEvent) => {
|
||||
const {height} = event.nativeEvent.layout;
|
||||
setCalendarHeight(height);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<View
|
||||
style={{flex: 1, backgroundColor: "#fff", borderRadius: 30}}
|
||||
ref={calendarContainerRef}
|
||||
onLayout={onLayout}
|
||||
>
|
||||
<CalendarHeader/>
|
||||
{calendarHeight > 0 && (
|
||||
<EventCalendar
|
||||
calendarHeight={calendarHeight}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<CalendarViewSwitch/>
|
||||
|
||||
<AddEventDialog/>
|
||||
<EditEventDialog/>
|
||||
<ManuallyAddEventModal/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -1,65 +1,55 @@
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
ButtonSize,
|
||||
Colors,
|
||||
DateTimePicker,
|
||||
LoaderScreen,
|
||||
Modal,
|
||||
Picker,
|
||||
Switch,
|
||||
Text,
|
||||
TextField,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from "react-native-ui-lib";
|
||||
import { ScrollView } from "react-native-gesture-handler";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
AntDesign,
|
||||
Feather,
|
||||
Ionicons,
|
||||
MaterialIcons,
|
||||
} from "@expo/vector-icons";
|
||||
import { PickerMultiValue } from "react-native-ui-lib/src/components/picker/types";
|
||||
import { useAuthContext } from "@/contexts/AuthContext";
|
||||
import { useCreateEvent } from "@/hooks/firebase/useCreateEvent";
|
||||
import { EventData } from "@/hooks/firebase/types/eventData";
|
||||
import { addHours, setDate } from "date-fns";
|
||||
import {ScrollView} from "react-native-gesture-handler";
|
||||
import {useSafeAreaInsets} from "react-native-safe-area-context";
|
||||
import {useState} from "react";
|
||||
import {AntDesign, Feather, Ionicons,} from "@expo/vector-icons";
|
||||
import {PickerMultiValue} from "react-native-ui-lib/src/components/picker/types";
|
||||
import {useCreateEvent} from "@/hooks/firebase/useCreateEvent";
|
||||
import {EventData} from "@/hooks/firebase/types/eventData";
|
||||
import {addHours} from "date-fns";
|
||||
import DropModalIcon from "@/assets/svgs/DropModalIcon";
|
||||
import { CalendarEvent, useCalendarContext } from "@/contexts/CalendarContext";
|
||||
import { repeatOptions } from "@/contexts/ToDosContext";
|
||||
import { ImageBackground, StyleSheet } from "react-native";
|
||||
import {StyleSheet} from "react-native";
|
||||
import ClockIcon from "@/assets/svgs/ClockIcon";
|
||||
import LockIcon from "@/assets/svgs/LockIcon";
|
||||
import MenuIcon from "@/assets/svgs/MenuIcon";
|
||||
import CameraIcon from "@/assets/svgs/CameraIcon";
|
||||
import AssigneesDisplay from "@/components/shared/AssigneesDisplay";
|
||||
import {useAtom} from "jotai";
|
||||
import {selectedNewEventDateAtom} from "@/components/pages/calendar/atoms";
|
||||
|
||||
const daysOfWeek = [
|
||||
{ label: "Monday", value: "monday" },
|
||||
{ label: "Tuesday", value: "tuesday" },
|
||||
{ label: "Wednesday", value: "wednesday" },
|
||||
{ label: "Thursday", value: "thursday" },
|
||||
{ label: "Friday", value: "friday" },
|
||||
{ label: "Saturday", value: "saturday" },
|
||||
{ label: "Sunday", value: "sunday" },
|
||||
{label: "Monday", value: "monday"},
|
||||
{label: "Tuesday", value: "tuesday"},
|
||||
{label: "Wednesday", value: "wednesday"},
|
||||
{label: "Thursday", value: "thursday"},
|
||||
{label: "Friday", value: "friday"},
|
||||
{label: "Saturday", value: "saturday"},
|
||||
{label: "Sunday", value: "sunday"},
|
||||
];
|
||||
|
||||
export const ManuallyAddEventModal = ({
|
||||
show,
|
||||
close,
|
||||
initialDate,
|
||||
}: {
|
||||
show: boolean;
|
||||
close: () => void;
|
||||
initialDate?: Date;
|
||||
}) => {
|
||||
const { addEvent } = useCalendarContext();
|
||||
const { user } = useAuthContext();
|
||||
export const ManuallyAddEventModal = () => {
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
const [selectedNewEventDate, setSelectedNewEndDate] = useAtom(selectedNewEventDateAtom)
|
||||
|
||||
const {show, close, initialDate} = {
|
||||
show: !!selectedNewEventDate,
|
||||
close: () => setSelectedNewEndDate(undefined),
|
||||
initialDate: selectedNewEventDate
|
||||
}
|
||||
|
||||
const [title, setTitle] = useState<string>("");
|
||||
|
||||
const [isAllDay, setIsAllDay] = useState(false);
|
||||
@ -82,7 +72,9 @@ export const ManuallyAddEventModal = ({
|
||||
|
||||
const [repeatInterval, setRepeatInterval] = useState<PickerMultiValue>([]);
|
||||
|
||||
const { mutateAsync: createEvent, isLoading, isError } = useCreateEvent();
|
||||
const {mutateAsync: createEvent, isLoading, isError} = useCreateEvent();
|
||||
|
||||
if (!selectedNewEventDate) return null;
|
||||
|
||||
const formatDateTime = (date?: Date | string) => {
|
||||
if (!date) return undefined;
|
||||
@ -166,7 +158,7 @@ export const ManuallyAddEventModal = ({
|
||||
onRequestClose={close}
|
||||
transparent={false}
|
||||
>
|
||||
<LoaderScreen message={"Saving event..."} color={Colors.grey40} />
|
||||
<LoaderScreen message={"Saving event..."} color={Colors.grey40}/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@ -207,7 +199,7 @@ export const ManuallyAddEventModal = ({
|
||||
Cancel
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<DropModalIcon onPress={close} />
|
||||
<DropModalIcon onPress={close}/>
|
||||
<TouchableOpacity onPress={handleSave}>
|
||||
<Text
|
||||
style={{
|
||||
@ -230,16 +222,16 @@ export const ManuallyAddEventModal = ({
|
||||
setTitle(text);
|
||||
}}
|
||||
placeholderTextColor="#2d2d30"
|
||||
style={{ fontFamily: "Manrope_500Medium", fontSize: 22 }}
|
||||
style={{fontFamily: "Manrope_500Medium", fontSize: 22}}
|
||||
paddingT-15
|
||||
paddingL-30
|
||||
returnKeyType="next"
|
||||
/>
|
||||
<View style={styles.divider} marginT-8 />
|
||||
<View style={styles.divider} marginT-8/>
|
||||
<View marginL-30 centerV>
|
||||
<View row spread marginB-10 centerV>
|
||||
<View row>
|
||||
<AntDesign name="clockcircleo" size={24} color="#919191" />
|
||||
<AntDesign name="clockcircleo" size={24} color="#919191"/>
|
||||
<Text
|
||||
style={{
|
||||
fontFamily: "PlusJakartaSans_500Medium",
|
||||
@ -262,7 +254,7 @@ export const ManuallyAddEventModal = ({
|
||||
</View>
|
||||
<View row marginB-10 spread>
|
||||
<View row centerV>
|
||||
<Feather name="calendar" size={25} color="#919191" />
|
||||
<Feather name="calendar" size={25} color="#919191"/>
|
||||
<DateTimePicker
|
||||
value={startDate}
|
||||
onChange={(date) => {
|
||||
@ -299,7 +291,7 @@ export const ManuallyAddEventModal = ({
|
||||
{!isAllDay && (
|
||||
<View row marginB-10 spread>
|
||||
<View row centerV>
|
||||
<Feather name="calendar" size={25} color="#919191" />
|
||||
<Feather name="calendar" size={25} color="#919191"/>
|
||||
<DateTimePicker
|
||||
value={endDate}
|
||||
minimumDate={startDate}
|
||||
@ -336,12 +328,12 @@ export const ManuallyAddEventModal = ({
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View style={styles.divider} />
|
||||
<View style={styles.divider}/>
|
||||
|
||||
<View marginH-30 marginB-10 row centerV>
|
||||
<Ionicons name="person-circle-outline" size={28} color="#919191" />
|
||||
<Ionicons name="person-circle-outline" size={28} color="#919191"/>
|
||||
<Text
|
||||
style={{ fontFamily: "Manrope_600SemiBold", fontSize: 18 }}
|
||||
style={{fontFamily: "Manrope_600SemiBold", fontSize: 18}}
|
||||
marginL-10
|
||||
>
|
||||
Attendees
|
||||
@ -350,7 +342,7 @@ export const ManuallyAddEventModal = ({
|
||||
size={ButtonSize.small}
|
||||
paddingH-8
|
||||
iconSource={() => (
|
||||
<Ionicons name="add-outline" size={20} color="#ea156c" />
|
||||
<Ionicons name="add-outline" size={20} color="#ea156c"/>
|
||||
)}
|
||||
style={{
|
||||
marginLeft: "auto",
|
||||
@ -361,16 +353,16 @@ export const ManuallyAddEventModal = ({
|
||||
}}
|
||||
color="#ea156c"
|
||||
label="Add"
|
||||
labelStyle={{ fontFamily: "Manrope_600SemiBold", fontSize: 14 }}
|
||||
labelStyle={{fontFamily: "Manrope_600SemiBold", fontSize: 14}}
|
||||
/>
|
||||
</View>
|
||||
<View marginL-35>
|
||||
<AssigneesDisplay />
|
||||
<AssigneesDisplay/>
|
||||
</View>
|
||||
<View style={styles.divider} />
|
||||
<View style={styles.divider}/>
|
||||
<View marginH-30 marginB-0 row spread centerV>
|
||||
<View row centerV>
|
||||
<ClockIcon />
|
||||
<ClockIcon/>
|
||||
<Text
|
||||
style={{
|
||||
fontFamily: "Manrope_600SemiBold",
|
||||
@ -386,7 +378,7 @@ export const ManuallyAddEventModal = ({
|
||||
size={ButtonSize.small}
|
||||
paddingH-8
|
||||
iconSource={() => (
|
||||
<Ionicons name="add-outline" size={20} color="#ea156c" />
|
||||
<Ionicons name="add-outline" size={20} color="#ea156c"/>
|
||||
)}
|
||||
style={{
|
||||
marginLeft: "auto",
|
||||
@ -395,16 +387,16 @@ export const ManuallyAddEventModal = ({
|
||||
borderColor: "#ea156c",
|
||||
borderWidth: 1,
|
||||
}}
|
||||
labelStyle={{ fontFamily: "Manrope_600SemiBold", fontSize: 14 }}
|
||||
labelStyle={{fontFamily: "Manrope_600SemiBold", fontSize: 14}}
|
||||
color="#ea156c"
|
||||
label="Set Reminder"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.divider} />
|
||||
<View style={styles.divider}/>
|
||||
<View marginH-30 marginB-0 row spread centerV>
|
||||
<View row>
|
||||
<LockIcon />
|
||||
<LockIcon/>
|
||||
<Text
|
||||
style={{
|
||||
fontFamily: "PlusJakartaSans_500Medium",
|
||||
@ -425,10 +417,10 @@ export const ManuallyAddEventModal = ({
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.divider} />
|
||||
<View style={styles.divider}/>
|
||||
<View marginH-30 marginB-0 row spread centerV>
|
||||
<View row centerV>
|
||||
<MenuIcon />
|
||||
<MenuIcon/>
|
||||
<Text
|
||||
style={{
|
||||
fontFamily: "PlusJakartaSans_500Medium",
|
||||
@ -447,12 +439,12 @@ export const ManuallyAddEventModal = ({
|
||||
marginB-15
|
||||
label="Create event from image"
|
||||
text70
|
||||
style={{ height: 47 }}
|
||||
labelStyle={{ fontFamily: "PlusJakartaSans_500Medium", fontSize: 15 }}
|
||||
style={{height: 47}}
|
||||
labelStyle={{fontFamily: "PlusJakartaSans_500Medium", fontSize: 15}}
|
||||
backgroundColor="#05a8b6"
|
||||
iconSource={() => (
|
||||
<View marginR-5>
|
||||
<CameraIcon color="white" />
|
||||
<CameraIcon color="white"/>
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
@ -462,7 +454,7 @@ export const ManuallyAddEventModal = ({
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
divider: { height: 1, backgroundColor: "#e4e4e4", marginVertical: 15 },
|
||||
divider: {height: 1, backgroundColor: "#e4e4e4", marginVertical: 15},
|
||||
gradient: {
|
||||
height: "25%",
|
||||
position: "absolute",
|
||||
|
||||
9
components/pages/calendar/atoms.ts
Normal file
9
components/pages/calendar/atoms.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { atom } from 'jotai';
|
||||
import {CalendarEvent} from "@/components/pages/calendar/interfaces";
|
||||
|
||||
export const editVisibleAtom = atom<boolean>(false);
|
||||
export const eventForEditAtom = atom<CalendarEvent | undefined>(undefined);
|
||||
export const isFamilyViewAtom = atom<boolean>(false);
|
||||
export const modeAtom = atom<"week" | "month" | "day">("week");
|
||||
export const selectedDateAtom = atom<Date>(new Date());
|
||||
export const selectedNewEventDateAtom = atom<Date | undefined>(undefined);
|
||||
20
components/pages/calendar/constants.ts
Normal file
20
components/pages/calendar/constants.ts
Normal file
@ -0,0 +1,20 @@
|
||||
export const modeMap = new Map([
|
||||
[0, "day"],
|
||||
[1, "week"],
|
||||
[2, "month"],
|
||||
]);
|
||||
|
||||
export const months = [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December",
|
||||
];
|
||||
13
components/pages/calendar/interfaces.ts
Normal file
13
components/pages/calendar/interfaces.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export interface CalendarEvent {
|
||||
id?: number | string; // Unique identifier for the event
|
||||
user?: string;
|
||||
title: string; // Event title or name
|
||||
description?: string; // Optional description for the event
|
||||
start: Date; // Start date and time of the event
|
||||
end: Date; // End date and time of the event
|
||||
location?: string; // Optional event location
|
||||
allDay?: boolean; // Specifies if the event lasts all day
|
||||
eventColor?: string; // Optional color to represent the event
|
||||
participants?: string[]; // Optional list of participants or attendees
|
||||
private?: boolean;
|
||||
}
|
||||
@ -1,17 +1,17 @@
|
||||
import {Button, ButtonSize, Dialog, Text, TextField, View} from "react-native-ui-lib";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import React, {useState} from "react";
|
||||
import {useSignIn} from "@/hooks/firebase/useSignIn";
|
||||
import {StyleSheet} from "react-native";
|
||||
import Toast from 'react-native-toast-message';
|
||||
import {useLoginWithQrCode} from "@/hooks/firebase/useLoginWithQrCode";
|
||||
import {Camera, CameraView} from 'expo-camera';
|
||||
import {BarCodeScanner} from "expo-barcode-scanner";
|
||||
|
||||
const SignInPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"register" | "login" | "reset-password">> }) => {
|
||||
const SignInPage = ({setTab}: {
|
||||
setTab: React.Dispatch<React.SetStateAction<"register" | "login" | "reset-password">>
|
||||
}) => {
|
||||
const [email, setEmail] = useState<string>("");
|
||||
const [password, setPassword] = useState<string>("");
|
||||
const [hasPermission, setHasPermission] = useState<boolean | null>(null);
|
||||
const [scanned, setScanned] = useState<boolean>(false);
|
||||
const [showCameraDialog, setShowCameraDialog] = useState<boolean>(false);
|
||||
|
||||
const {mutateAsync: signIn, error, isError} = useSignIn();
|
||||
@ -19,7 +19,7 @@ const SignInPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"re
|
||||
|
||||
const handleSignIn = async () => {
|
||||
await signIn({email, password});
|
||||
if(!isError) {
|
||||
if (!isError) {
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Login successful!"
|
||||
@ -33,10 +33,10 @@ const SignInPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"re
|
||||
}
|
||||
};
|
||||
|
||||
const handleQrCodeScanned = async ({ data }: { data: string }) => {
|
||||
const handleQrCodeScanned = async ({data}: { data: string }) => {
|
||||
setShowCameraDialog(false);
|
||||
try {
|
||||
await signInWithQrCode({ userId: data });
|
||||
await signInWithQrCode({userId: data});
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Login successful with QR code!"
|
||||
@ -51,9 +51,9 @@ const SignInPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"re
|
||||
};
|
||||
|
||||
const getCameraPermissions = async (callback: () => void) => {
|
||||
const { status } = await Camera.requestCameraPermissionsAsync();
|
||||
const {status} = await Camera.requestCameraPermissionsAsync();
|
||||
setHasPermission(status === 'granted');
|
||||
if(status === 'granted') {
|
||||
if (status === 'granted') {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
@ -88,7 +88,7 @@ const SignInPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"re
|
||||
style={{marginBottom: 20}}
|
||||
backgroundColor="#fd1775"
|
||||
/>
|
||||
{isError && <Text center style={{marginBottom: 20}}>{`${error}`}</Text>}
|
||||
{isError && <Text center style={{marginBottom: 20}}>{`${error?.toString()?.split("]")?.[1]}`}</Text>}
|
||||
|
||||
<View row centerH marginB-5 gap-5>
|
||||
<Text text70>
|
||||
@ -131,7 +131,7 @@ const SignInPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"re
|
||||
bottom
|
||||
width="100%"
|
||||
height="70%"
|
||||
containerStyle={{ padding: 0 }}
|
||||
containerStyle={{padding: 0}}
|
||||
>
|
||||
{hasPermission === null ? (
|
||||
<Text>Requesting camera permissions...</Text>
|
||||
@ -139,7 +139,7 @@ const SignInPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"re
|
||||
<Text>No access to camera</Text>
|
||||
) : (
|
||||
<CameraView
|
||||
style={{ flex: 1 }}
|
||||
style={{flex: 1}}
|
||||
onBarcodeScanned={handleQrCodeScanned}
|
||||
barcodeScannerSettings={{
|
||||
barcodeTypes: ["qr"],
|
||||
@ -150,7 +150,7 @@ const SignInPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"re
|
||||
label="Cancel"
|
||||
onPress={() => setShowCameraDialog(false)}
|
||||
backgroundColor="#fd1775"
|
||||
style={{ margin: 10 }}
|
||||
style={{margin: 10}}
|
||||
/>
|
||||
</Dialog>
|
||||
</View>
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
import { View, Text, Button } from "react-native-ui-lib";
|
||||
import React, { useState } from "react";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { Entypo, Ionicons, Octicons } from "@expo/vector-icons";
|
||||
import {Button, Text, View} from "react-native-ui-lib";
|
||||
import React, {useState} from "react";
|
||||
import {StyleSheet} from "react-native";
|
||||
import {Octicons} from "@expo/vector-icons";
|
||||
import CalendarSettingsPage from "./CalendarSettingsPage";
|
||||
import ChoreRewardSettings from "./ChoreRewardSettings";
|
||||
import UserSettings from "./UserSettings";
|
||||
import { AuthContextProvider } from "@/contexts/AuthContext";
|
||||
import ProfileIcon from "@/assets/svgs/ProfileIcon";
|
||||
import CalendarIcon from "@/assets/svgs/CalendarIcon";
|
||||
import PrivacyPolicyIcon from "@/assets/svgs/PrivacyPolicyIcon";
|
||||
@ -18,6 +17,7 @@ const pageIndex = {
|
||||
chore: 3,
|
||||
policy: 4,
|
||||
};
|
||||
|
||||
const SettingsPage = () => {
|
||||
const [selectedPage, setSelectedPage] = useState<number>(0);
|
||||
return (
|
||||
@ -29,11 +29,11 @@ const SettingsPage = () => {
|
||||
style={styles.mainBtn}
|
||||
children={
|
||||
<View row centerV width={"100%"}>
|
||||
<ProfileIcon style={{ marginRight: 10 }} color="#07b9c8" />
|
||||
<ProfileIcon style={{marginRight: 10}} color="#07b9c8"/>
|
||||
<Text style={styles.label} color="#07b8c7">
|
||||
Manage My Profile
|
||||
</Text>
|
||||
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||
<ArrowRightIcon style={{marginLeft: "auto"}}/>
|
||||
</View>
|
||||
}
|
||||
onPress={() => setSelectedPage(pageIndex.user)}
|
||||
@ -43,11 +43,11 @@ const SettingsPage = () => {
|
||||
style={styles.mainBtn}
|
||||
children={
|
||||
<View row centerV width={"100%"}>
|
||||
<CalendarIcon style={{ marginRight: 10 }} />
|
||||
<CalendarIcon style={{marginRight: 10}}/>
|
||||
<Text style={styles.label} color="#fd1775">
|
||||
Calendar Settings
|
||||
</Text>
|
||||
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||
<ArrowRightIcon style={{marginLeft: "auto"}}/>
|
||||
</View>
|
||||
}
|
||||
onPress={() => {
|
||||
@ -63,12 +63,12 @@ const SettingsPage = () => {
|
||||
name="gear"
|
||||
size={24}
|
||||
color="#ff9900"
|
||||
style={{ marginRight: 10 }}
|
||||
style={{marginRight: 10}}
|
||||
/>
|
||||
<Text style={styles.label} color="#ff9900">
|
||||
To-Do Reward Settings
|
||||
</Text>
|
||||
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||
<ArrowRightIcon style={{marginLeft: "auto"}}/>
|
||||
</View>
|
||||
}
|
||||
onPress={() => setSelectedPage(pageIndex.chore)}
|
||||
@ -78,24 +78,24 @@ const SettingsPage = () => {
|
||||
style={styles.mainBtn}
|
||||
children={
|
||||
<View row centerV width={"100%"}>
|
||||
<PrivacyPolicyIcon style={{ marginRight: 10 }} />
|
||||
<PrivacyPolicyIcon style={{marginRight: 10}}/>
|
||||
<Text style={styles.label} color="#6c645b">
|
||||
Cally Privacy Policy
|
||||
</Text>
|
||||
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||
<ArrowRightIcon style={{marginLeft: "auto"}}/>
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
{selectedPage == pageIndex.calendar && (
|
||||
<CalendarSettingsPage setSelectedPage={setSelectedPage} />
|
||||
<CalendarSettingsPage setSelectedPage={setSelectedPage}/>
|
||||
)}
|
||||
{selectedPage == pageIndex.chore && (
|
||||
<ChoreRewardSettings setSelectedPage={setSelectedPage} />
|
||||
<ChoreRewardSettings setSelectedPage={setSelectedPage}/>
|
||||
)}
|
||||
{selectedPage == pageIndex.user && (
|
||||
<UserSettings setSelectedPage={setSelectedPage} />
|
||||
<UserSettings setSelectedPage={setSelectedPage}/>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
|
||||
@ -99,6 +99,7 @@ export const AuthContextProvider: FC<{ children: ReactNode }> = ({children}) =>
|
||||
const onAuthStateChangedHandler = async (authUser: FirebaseAuthTypes.User | null) => {
|
||||
setUser(authUser);
|
||||
|
||||
|
||||
if (authUser) {
|
||||
await refreshProfileData(authUser);
|
||||
const pushToken = await registerForPushNotificationsAsync();
|
||||
|
||||
@ -1,194 +0,0 @@
|
||||
// CalendarContext.tsx
|
||||
import React, { createContext, useContext, useState, ReactNode } from "react";
|
||||
|
||||
// Define the CalendarEvent interface
|
||||
export interface CalendarEvent {
|
||||
id?: number | string; // Unique identifier for the event
|
||||
user?: string;
|
||||
title: string; // Event title or name
|
||||
description?: string; // Optional description for the event
|
||||
start: Date; // Start date and time of the event
|
||||
end: Date; // End date and time of the event
|
||||
location?: string; // Optional event location
|
||||
allDay?: boolean; // Specifies if the event lasts all day
|
||||
color?: string; // Optional color to represent the event
|
||||
participants?: string[]; // Optional list of participants or attendees
|
||||
private?: boolean;
|
||||
}
|
||||
|
||||
// Define the context type
|
||||
interface CalendarContextType {
|
||||
events: CalendarEvent[];
|
||||
familyEvents: CalendarEvent[];
|
||||
addEvent: (event: CalendarEvent) => void; // Function to add an event
|
||||
removeEvent: (id: number) => void; // Function to remove an event by ID
|
||||
updateEvent: (changes: Partial<CalendarEvent>, id?: number) => void;
|
||||
}
|
||||
|
||||
// Create the CalendarContext
|
||||
const CalendarContext = createContext<CalendarContextType | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
// Create a provider component
|
||||
export const CalendarProvider: React.FC<{ children: ReactNode }> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [events, setEvents] = useState<CalendarEvent[]>([
|
||||
{
|
||||
id: 1,
|
||||
title: "Team Meeting",
|
||||
description: "Discuss project milestones and deadlines.",
|
||||
start: new Date("2024-09-15T10:00:00"),
|
||||
end: new Date("2024-09-15T11:00:00"),
|
||||
location: "Office Conference Room",
|
||||
allDay: false,
|
||||
color: "#FF5733",
|
||||
participants: ["Alice", "Bob", "Charlie"],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Doctor's Appointment",
|
||||
description: "Annual check-up with Dr. Smith.",
|
||||
start: new Date("2024-09-20T14:30:00"),
|
||||
end: new Date("2024-09-20T15:30:00"),
|
||||
location: "Health Clinic",
|
||||
allDay: false,
|
||||
color: "#33FF57",
|
||||
participants: ["You"],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Birthday Party",
|
||||
description: "Celebrating Sarah's 30th birthday.",
|
||||
start: new Date("2024-09-25T18:00:00"),
|
||||
end: new Date("2024-09-25T21:00:00"),
|
||||
location: "Sarah's House",
|
||||
allDay: false,
|
||||
color: "#3357FF",
|
||||
participants: ["You", "Sarah", "Tom", "Lily"],
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "Project Deadline",
|
||||
description: "Final submission for the project.",
|
||||
start: new Date("2024-10-01T00:00:00"),
|
||||
end: new Date("2024-10-01T23:59:00"),
|
||||
location: "Online",
|
||||
allDay: false,
|
||||
color: "#FF33A1",
|
||||
participants: ["You"],
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: "Halloween Costume Party",
|
||||
description: "Join us for a spooky night of fun!",
|
||||
start: new Date("2024-10-31T19:00:00"),
|
||||
end: new Date("2024-10-31T23:00:00"),
|
||||
location: "Downtown Club",
|
||||
allDay: false,
|
||||
color: "#FFB733",
|
||||
participants: ["You", "Friends"],
|
||||
},
|
||||
]);
|
||||
|
||||
const [familyEvents, setFamilyEvents] = useState<CalendarEvent[]>([
|
||||
{
|
||||
id: 1,
|
||||
user: "jakesId",
|
||||
title: "Team Meeting",
|
||||
description: "Discuss project milestones and deadlines.",
|
||||
start: new Date("2024-09-10T10:00:00"),
|
||||
end: new Date("2024-09-10T11:00:00"),
|
||||
location: "Office Conference Room",
|
||||
allDay: false,
|
||||
color: "#FF5733",
|
||||
participants: ["Alice", "Bob", "Charlie"],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
user: "mikesId",
|
||||
title: "Doctor's Appointment",
|
||||
description: "Annual check-up with Dr. Smith.",
|
||||
start: new Date("2024-09-21T14:30:00"),
|
||||
end: new Date("2024-09-21T15:30:00"),
|
||||
location: "Health Clinic",
|
||||
allDay: false,
|
||||
color: "#33FF57",
|
||||
participants: ["You"],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
user: "jakesId",
|
||||
title: "Birthday Party",
|
||||
description: "Celebrating Sarah's 30th birthday.",
|
||||
start: new Date("2024-09-5T18:00:00"),
|
||||
end: new Date("2024-09-5T21:00:00"),
|
||||
location: "Sarah's House",
|
||||
allDay: false,
|
||||
color: "#3357FF",
|
||||
participants: ["You", "Sarah", "Tom", "Lily"],
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
user: "davidsId",
|
||||
title: "Project Deadline",
|
||||
description: "Final submission for the project.",
|
||||
start: new Date("2024-10-03T00:00:00"),
|
||||
end: new Date("2024-10-03T23:59:00"),
|
||||
location: "Online",
|
||||
allDay: false,
|
||||
color: "#FF33A1",
|
||||
participants: ["You"],
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
user: "jakesId",
|
||||
title: "Halloween Costume Party",
|
||||
description: "Join us for a spooky night of fun!",
|
||||
start: new Date("2024-10-02T19:00:00"),
|
||||
end: new Date("2024-10-02T23:00:00"),
|
||||
location: "Downtown Club",
|
||||
allDay: false,
|
||||
color: "#FFB733",
|
||||
participants: ["You", "Friends"],
|
||||
},
|
||||
]);
|
||||
|
||||
// Function to add an event
|
||||
const addEvent = (event: CalendarEvent) => {
|
||||
event.id = events.length + 1;
|
||||
setEvents((prevEvents) => [...prevEvents, event]);
|
||||
};
|
||||
|
||||
// Function to remove an event by ID
|
||||
const removeEvent = (id: number) => {
|
||||
setEvents((prevEvents) => prevEvents.filter((event) => event.id !== id));
|
||||
};
|
||||
|
||||
// Function to update an event
|
||||
const updateEvent = ( changes: Partial<CalendarEvent>, id?: number) => {
|
||||
setEvents((prevEvents) =>
|
||||
prevEvents.map((event) =>
|
||||
event.id === id ? { ...event, ...changes } : event
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<CalendarContext.Provider
|
||||
value={{ events, addEvent, removeEvent, updateEvent, familyEvents }}
|
||||
>
|
||||
{children}
|
||||
</CalendarContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
// Custom hook to use the CalendarContext
|
||||
export const useCalendarContext = () => {
|
||||
const context = useContext(CalendarContext);
|
||||
if (!context) {
|
||||
throw new Error("useCalendar must be used within a CalendarProvider");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@ -10,5 +10,5 @@ export interface EventData {
|
||||
surpriseEvent?: boolean,
|
||||
notes?: string,
|
||||
reminders?: string[]
|
||||
id?: string,
|
||||
id?: string | number,
|
||||
}
|
||||
@ -2,9 +2,12 @@ import {useQuery} from "react-query";
|
||||
import firestore from "@react-native-firebase/firestore";
|
||||
import {useAuthContext} from "@/contexts/AuthContext";
|
||||
import {colorMap} from "@/contexts/SettingsContext";
|
||||
import {useAtomValue} from "jotai";
|
||||
import {isFamilyViewAtom} from "@/components/pages/calendar/atoms";
|
||||
|
||||
export const useGetEvents = (isFamilyView: boolean) => {
|
||||
export const useGetEvents = () => {
|
||||
const { user, profileData } = useAuthContext();
|
||||
const isFamilyView = useAtomValue(isFamilyViewAtom)
|
||||
|
||||
return useQuery({
|
||||
queryKey: ["events", user?.uid, isFamilyView],
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
import {useAuthContext} from "@/contexts/AuthContext";
|
||||
import {useMutation, useQueryClient} from "react-query";
|
||||
import firestore from "@react-native-firebase/firestore";
|
||||
import {EventData} from "@/hooks/firebase/types/eventData";
|
||||
|
||||
export const useUpdateEvent = () => {
|
||||
const {user: currentUser} = useAuthContext()
|
||||
const queryClients = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
@ -13,7 +11,7 @@ export const useUpdateEvent = () => {
|
||||
try {
|
||||
await firestore()
|
||||
.collection("Events")
|
||||
.doc(eventData.id)
|
||||
.doc(`${eventData.id}`)
|
||||
.update(eventData);
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
|
||||
@ -441,7 +441,7 @@
|
||||
);
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.cally.app;
|
||||
PRODUCT_NAME = "CallyFamilyPlanner";
|
||||
PRODUCT_NAME = CallyFamilyPlanner;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "cally/cally-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@ -472,7 +472,7 @@
|
||||
);
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.cally.app;
|
||||
PRODUCT_NAME = "CallyFamilyPlanner";
|
||||
PRODUCT_NAME = CallyFamilyPlanner;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "cally/cally-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
||||
Reference in New Issue
Block a user