mirror of
https://github.com/urosran/cally.git
synced 2025-07-15 09:45:20 +00:00
Event creation
This commit is contained in:
@ -1,12 +1,69 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import {Drawer} from "expo-router/drawer";
|
import {Drawer} from "expo-router/drawer";
|
||||||
|
import {useSignOut} from "@/hooks/firebase/useSignOut";
|
||||||
|
import {DrawerContentScrollView, DrawerItem, DrawerItemList} from "@react-navigation/drawer";
|
||||||
|
|
||||||
export default function TabLayout() {
|
export default function TabLayout() {
|
||||||
return (
|
const {mutateAsync: signOut} = useSignOut()
|
||||||
<Drawer
|
|
||||||
screenOptions={{
|
return (
|
||||||
headerShown: true,
|
<Drawer
|
||||||
}}/>
|
initialRouteName={"index"}
|
||||||
);
|
screenOptions={{
|
||||||
|
headerShown: true,
|
||||||
|
}}
|
||||||
|
drawerContent={props => {
|
||||||
|
return (
|
||||||
|
<DrawerContentScrollView {...props}>
|
||||||
|
<DrawerItemList {...props} />
|
||||||
|
<DrawerItem label="Logout" onPress={() => signOut()}/>
|
||||||
|
</DrawerContentScrollView>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Drawer.Screen
|
||||||
|
name="index"
|
||||||
|
options={{
|
||||||
|
drawerLabel: "Calendar",
|
||||||
|
title: "Calendar",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Drawer.Screen
|
||||||
|
name="calendar"
|
||||||
|
options={{
|
||||||
|
drawerLabel: "Calendar",
|
||||||
|
title: "Calendar",
|
||||||
|
drawerItemStyle: {display: "none"}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Drawer.Screen
|
||||||
|
name="brain_dump"
|
||||||
|
options={{
|
||||||
|
drawerLabel: "Brain Dump",
|
||||||
|
title: "Brain Dump",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Drawer.Screen
|
||||||
|
name="grocery"
|
||||||
|
options={{
|
||||||
|
drawerLabel: "Grocery",
|
||||||
|
title: "Grocery",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Drawer.Screen
|
||||||
|
name="reminders"
|
||||||
|
options={{
|
||||||
|
drawerLabel: "Reminders",
|
||||||
|
title: "Reminders",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Drawer.Screen
|
||||||
|
name="todos"
|
||||||
|
options={{
|
||||||
|
drawerLabel: "To-Do",
|
||||||
|
title: "To-Do",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,123 @@
|
|||||||
import {View} from "react-native-ui-lib";
|
import React, {useRef, useState} from "react";
|
||||||
|
import {LayoutChangeEvent} from "react-native";
|
||||||
|
import {Calendar} from "react-native-big-calendar";
|
||||||
|
import {Button, Picker, PickerModes, SegmentedControl, Text, View} from "react-native-ui-lib";
|
||||||
|
import {MaterialIcons} from "@expo/vector-icons";
|
||||||
|
import {AddEventDialog} from "@/components/pages/calendar/AddEventDialog";
|
||||||
|
import {useGetEvents} from "@/hooks/firebase/useGetEvents";
|
||||||
|
|
||||||
|
const modeMap = new Map([
|
||||||
|
[0, "day"],
|
||||||
|
[1, "week"],
|
||||||
|
[2, "month"]
|
||||||
|
]);
|
||||||
|
|
||||||
|
const months = [
|
||||||
|
"January", "February", "March", "April", "May", "June",
|
||||||
|
"July", "August", "September", "October", "November", "December"
|
||||||
|
];
|
||||||
|
|
||||||
export default function Screen() {
|
export default function Screen() {
|
||||||
|
const [calendarHeight, setCalendarHeight] = useState(0);
|
||||||
|
const [mode, setMode] = useState<"week" | "month" | "day">("week");
|
||||||
|
const [selectedDate, setSelectedDate] = useState<Date>(new Date());
|
||||||
|
|
||||||
|
const calendarContainerRef = useRef(null);
|
||||||
|
const { data: events} = useGetEvents()
|
||||||
|
|
||||||
|
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 "week" | "month" | "day");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMonthChange = (month: string) => {
|
||||||
|
const currentYear = selectedDate.getFullYear();
|
||||||
|
const currentDay = selectedDate.getDate();
|
||||||
|
const newMonthIndex = months.indexOf(month);
|
||||||
|
|
||||||
|
// Update the date with the new month while preserving the day and year
|
||||||
|
const updatedDate = new Date(currentYear, newMonthIndex, currentDay);
|
||||||
|
setSelectedDate(updatedDate);
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(events)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View/>
|
<View style={{flex: 1, height: "100%", padding: 10}}>
|
||||||
)
|
<View style={{height: 60, justifyContent: "space-evenly", alignItems: "flex-start"}}>
|
||||||
}
|
<Text>Welcome Dalia</Text>
|
||||||
|
<Text>Let's get your week started!</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<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: "#f9f9f9",
|
||||||
|
marginBottom: 10,
|
||||||
|
shadowColor: "#000",
|
||||||
|
shadowOffset: { width: 0, height: 2 },
|
||||||
|
shadowOpacity: 0.1,
|
||||||
|
shadowRadius: 5,
|
||||||
|
elevation: 3,
|
||||||
|
}}>
|
||||||
|
<Picker
|
||||||
|
value={months[selectedDate.getMonth()]} // Get the month from the date
|
||||||
|
placeholder={"Select Month"}
|
||||||
|
mode={PickerModes.SINGLE}
|
||||||
|
onChange={(itemValue) => handleMonthChange(itemValue as string)}
|
||||||
|
trailingAccessory={<MaterialIcons name={"keyboard-arrow-down"}/>}
|
||||||
|
>
|
||||||
|
{months.map((month) => (
|
||||||
|
<Picker.Item key={month} label={month} value={month}/>
|
||||||
|
))}
|
||||||
|
</Picker>
|
||||||
|
|
||||||
|
<View>
|
||||||
|
<SegmentedControl
|
||||||
|
segments={[
|
||||||
|
{label: "D"},
|
||||||
|
{label: "W"},
|
||||||
|
{label: "M"}
|
||||||
|
]}
|
||||||
|
onChangeIndex={handleSegmentChange}
|
||||||
|
initialIndex={[...modeMap.entries()].find(([_, value]) => value === mode)?.[0] || 1}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{calendarHeight > 0 && (
|
||||||
|
<Calendar
|
||||||
|
mode={mode}
|
||||||
|
events={events ?? []}
|
||||||
|
height={calendarHeight}
|
||||||
|
activeDate={selectedDate}
|
||||||
|
onSwipeEnd={(newDate) => {
|
||||||
|
console.log(newDate)
|
||||||
|
setSelectedDate(newDate);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<AddEventDialog/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -1,70 +1,3 @@
|
|||||||
import { Image, StyleSheet, Platform } from 'react-native';
|
import Screen from "@/app/(auth)/calendar";
|
||||||
|
|
||||||
import { HelloWave } from '@/components/HelloWave';
|
export default Screen
|
||||||
import ParallaxScrollView from '@/components/ParallaxScrollView';
|
|
||||||
import { ThemedText } from '@/components/ThemedText';
|
|
||||||
import { ThemedView } from '@/components/ThemedView';
|
|
||||||
|
|
||||||
export default function HomeScreen() {
|
|
||||||
return (
|
|
||||||
<ParallaxScrollView
|
|
||||||
headerBackgroundColor={{ light: '#A1CEDC', dark: '#1D3D47' }}
|
|
||||||
headerImage={
|
|
||||||
<Image
|
|
||||||
source={require('@/assets/images/partial-react-logo.png')}
|
|
||||||
style={styles.reactLogo}
|
|
||||||
/>
|
|
||||||
}>
|
|
||||||
<ThemedView style={styles.titleContainer}>
|
|
||||||
<ThemedText type="title">Welcome!</ThemedText>
|
|
||||||
<HelloWave />
|
|
||||||
</ThemedView>
|
|
||||||
<ThemedView style={styles.stepContainer}>
|
|
||||||
<ThemedText type="subtitle">Step 1: Try it</ThemedText>
|
|
||||||
<ThemedText>
|
|
||||||
Edit <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> to see changes.
|
|
||||||
Press{' '}
|
|
||||||
<ThemedText type="defaultSemiBold">
|
|
||||||
{Platform.select({ ios: 'cmd + d', android: 'cmd + m' })}
|
|
||||||
</ThemedText>{' '}
|
|
||||||
to open developer tools.
|
|
||||||
</ThemedText>
|
|
||||||
</ThemedView>
|
|
||||||
<ThemedView style={styles.stepContainer}>
|
|
||||||
<ThemedText type="subtitle">Step 2: Explore</ThemedText>
|
|
||||||
<ThemedText>
|
|
||||||
Tap the Explore tab to learn more about what's included in this starter app.
|
|
||||||
</ThemedText>
|
|
||||||
</ThemedView>
|
|
||||||
<ThemedView style={styles.stepContainer}>
|
|
||||||
<ThemedText type="subtitle">Step 3: Get a fresh start</ThemedText>
|
|
||||||
<ThemedText>
|
|
||||||
When you're ready, run{' '}
|
|
||||||
<ThemedText type="defaultSemiBold">npm run reset-project</ThemedText> to get a fresh{' '}
|
|
||||||
<ThemedText type="defaultSemiBold">app</ThemedText> directory. This will move the current{' '}
|
|
||||||
<ThemedText type="defaultSemiBold">app</ThemedText> to{' '}
|
|
||||||
<ThemedText type="defaultSemiBold">app-example</ThemedText>.
|
|
||||||
</ThemedText>
|
|
||||||
</ThemedView>
|
|
||||||
</ParallaxScrollView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
titleContainer: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 8,
|
|
||||||
},
|
|
||||||
stepContainer: {
|
|
||||||
gap: 8,
|
|
||||||
marginBottom: 8,
|
|
||||||
},
|
|
||||||
reactLogo: {
|
|
||||||
height: 178,
|
|
||||||
width: 290,
|
|
||||||
bottom: 0,
|
|
||||||
left: 0,
|
|
||||||
position: 'absolute',
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,5 +0,0 @@
|
|||||||
import {Stack} from "expo-router";
|
|
||||||
|
|
||||||
export default function StackLayout () {
|
|
||||||
return <Stack screenOptions={{headerShown: false}}/>
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import { Button, TextInput } from "react-native";
|
|
||||||
import { Checkbox, Picker, TextField, View, Text } from "react-native-ui-lib";
|
|
||||||
import { useCreateSubUser } from "@/hooks/firebase/useCreateSubUser";
|
|
||||||
import { UserProfile } from "@/hooks/firebase/types/profileTypes";
|
|
||||||
import { uuidv4 } from "@firebase/util";
|
|
||||||
import { useGetChildrenByParentId } from "@/hooks/firebase/useGetChildrenByParentId";
|
|
||||||
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
|
||||||
import SignInPage from "../../../components/pages/main/SignInPage";
|
|
||||||
import Entry from "@/components/pages/main/Entry";
|
|
||||||
import { useSignUp } from "@/hooks/firebase/useSignUp";
|
|
||||||
import { useSignOut } from "@/hooks/firebase/useSignOut";
|
|
||||||
|
|
||||||
const Screen: React.FC = () => {
|
|
||||||
const { user, profileType, profileData } = useAuthContext();
|
|
||||||
|
|
||||||
const { data: children } = useGetChildrenByParentId();
|
|
||||||
|
|
||||||
const { mutateAsync: createSubUser } = useCreateSubUser();
|
|
||||||
const { mutateAsync: signOut } = useSignOut();
|
|
||||||
|
|
||||||
const createNewSubUser = async (userProfile: UserProfile) => {
|
|
||||||
await createSubUser({ ...userProfile, email: `${uuidv4()}@test.com` });
|
|
||||||
// createSubUser({
|
|
||||||
// email,
|
|
||||||
// password,
|
|
||||||
// userType: profileType!,
|
|
||||||
// name: "",
|
|
||||||
// contact: "+381628334",
|
|
||||||
// ...child
|
|
||||||
// })
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
{user ? (
|
|
||||||
<View paddingH-20 marginT-20>
|
|
||||||
{profileType === ProfileType.PARENT && <Text>Parent</Text>}
|
|
||||||
{profileType === ProfileType.CHILD && <Text>Child</Text>}
|
|
||||||
{profileType === ProfileType.CAREGIVER && <Text>Caregiver</Text>}
|
|
||||||
<Button title="Sign Out" onPress={async() => {await signOut()}} />
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<Entry />
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Screen;
|
|
@ -0,0 +1,5 @@
|
|||||||
|
import {Stack} from "expo-router";
|
||||||
|
|
||||||
|
export default function Layout() {
|
||||||
|
return <Stack screenOptions={{title: "Login"}}/>
|
||||||
|
}
|
7
app/(unauth)/index.tsx
Normal file
7
app/(unauth)/index.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import Entry from "@/components/pages/main/Entry";
|
||||||
|
|
||||||
|
export default function Screen() {
|
||||||
|
return (
|
||||||
|
<Entry/>
|
||||||
|
)
|
||||||
|
}
|
@ -1,15 +1,16 @@
|
|||||||
import { Link, Stack } from 'expo-router';
|
import {Link, Stack, usePathname} from 'expo-router';
|
||||||
import { StyleSheet } from 'react-native';
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
import { ThemedText } from '@/components/ThemedText';
|
import { ThemedText } from '@/components/ThemedText';
|
||||||
import { ThemedView } from '@/components/ThemedView';
|
import { ThemedView } from '@/components/ThemedView';
|
||||||
|
|
||||||
export default function NotFoundScreen() {
|
export default function NotFoundScreen() {
|
||||||
|
const route = usePathname()
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack.Screen options={{ title: 'Oops!' }} />
|
<Stack.Screen options={{ title: 'Oops!' }} />
|
||||||
<ThemedView style={styles.container}>
|
<ThemedView style={styles.container}>
|
||||||
<ThemedText type="title">This screen doesn't exist.</ThemedText>
|
<ThemedText type="title">This screen doesn't exist. ({route})</ThemedText>
|
||||||
<Link href="/" style={styles.link}>
|
<Link href="/" style={styles.link}>
|
||||||
<ThemedText type="link">Go to home screen!</ThemedText>
|
<ThemedText type="link">Go to home screen!</ThemedText>
|
||||||
</Link>
|
</Link>
|
||||||
|
89
components/pages/calendar/AddEventDialog.tsx
Normal file
89
components/pages/calendar/AddEventDialog.tsx
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import React, {useState} from "react";
|
||||||
|
import {MaterialIcons} from "@expo/vector-icons";
|
||||||
|
import {Button, Card, Dialog, PanningProvider, Text, View} from "react-native-ui-lib";
|
||||||
|
import {TouchableOpacity} from "react-native";
|
||||||
|
import {ManuallyAddEventModal} from "@/components/pages/calendar/ManuallyAddEventModal";
|
||||||
|
|
||||||
|
export const AddEventDialog = () => {
|
||||||
|
const [show, setShow] = useState(false);
|
||||||
|
const [showManualInputModal, setShowManualInputModal] = useState(false);
|
||||||
|
|
||||||
|
const handleOpenManualInputModal = () => {
|
||||||
|
setShow(false);
|
||||||
|
setTimeout(() => {
|
||||||
|
setShowManualInputModal(true);
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
bottom: 20,
|
||||||
|
right: 20,
|
||||||
|
height: 60,
|
||||||
|
width: 60,
|
||||||
|
borderRadius: 30,
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
enableShadow
|
||||||
|
iconSource={() => <MaterialIcons name="add" size={30}/>}
|
||||||
|
onPress={() => setShow(true)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
visible={show}
|
||||||
|
onDismiss={() => setShow(false)}
|
||||||
|
panDirection={PanningProvider.Directions.DOWN}
|
||||||
|
center
|
||||||
|
>
|
||||||
|
<Card style={{padding: 20, justifyContent: 'center', alignItems: "center"}}>
|
||||||
|
<Text text60>Create a new event</Text>
|
||||||
|
|
||||||
|
<View style={{marginTop: 20, alignItems: 'center'}}>
|
||||||
|
<Button
|
||||||
|
style={{
|
||||||
|
marginBottom: 10,
|
||||||
|
backgroundColor: "#007bff",
|
||||||
|
}}
|
||||||
|
onPress={handleOpenManualInputModal}
|
||||||
|
>
|
||||||
|
<Text style={{color: "white"}}>Manually Input</Text>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style={{
|
||||||
|
marginBottom: 10,
|
||||||
|
backgroundColor: "#007bff",
|
||||||
|
opacity: 0.5
|
||||||
|
}}
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
<Text style={{color: "white"}}>Scan an Image</Text>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style={{
|
||||||
|
marginBottom: 10,
|
||||||
|
backgroundColor: "#007bff",
|
||||||
|
opacity: 0.5
|
||||||
|
}}
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
<Text style={{color: "white"}}>Paste in text</Text>
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<TouchableOpacity onPress={() => setShow(false)}>
|
||||||
|
<Text style={{marginTop: 20, color: "#007bff"}}>Go back</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</Card>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<ManuallyAddEventModal show={showManualInputModal} close={() => setShowManualInputModal(false)}/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
260
components/pages/calendar/ManuallyAddEventModal.tsx
Normal file
260
components/pages/calendar/ManuallyAddEventModal.tsx
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
import {
|
||||||
|
Avatar,
|
||||||
|
Colors,
|
||||||
|
DateTimePicker,
|
||||||
|
LoaderScreen,
|
||||||
|
Modal,
|
||||||
|
Picker,
|
||||||
|
Switch,
|
||||||
|
Text,
|
||||||
|
TextField,
|
||||||
|
View
|
||||||
|
} from "react-native-ui-lib";
|
||||||
|
import {ScrollView, TouchableOpacity} from "react-native-gesture-handler";
|
||||||
|
import {useSafeAreaInsets} from "react-native-safe-area-context";
|
||||||
|
import {useState} from "react";
|
||||||
|
import {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";
|
||||||
|
|
||||||
|
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"},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const ManuallyAddEventModal = ({show, close}: { show: boolean, close: () => void }) => {
|
||||||
|
const {user} = useAuthContext()
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
|
|
||||||
|
const [title, setTitle] = useState<string>("");
|
||||||
|
|
||||||
|
const [isAllDay, setIsAllDay] = useState(false);
|
||||||
|
const [startTime, setStartTime] = useState(new Date());
|
||||||
|
const [endTime, setEndTime] = useState(new Date())
|
||||||
|
|
||||||
|
const [startDate, setStartDate] = useState(new Date());
|
||||||
|
const [endDate, setEndDate] = useState(new Date())
|
||||||
|
|
||||||
|
const [repeatInterval, setRepeatInterval] = useState<PickerMultiValue>([]);
|
||||||
|
|
||||||
|
const {mutateAsync: createEvent, isLoading, isError} = useCreateEvent()
|
||||||
|
|
||||||
|
const formatDateTime = (date: Date) => {
|
||||||
|
return date.toLocaleDateString('en-US', {
|
||||||
|
weekday: 'long',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const combineDateAndTime = (date: Date, time: Date): Date => {
|
||||||
|
const combined = new Date(date);
|
||||||
|
combined.setHours(time.getHours());
|
||||||
|
combined.setMinutes(time.getMinutes());
|
||||||
|
combined.setSeconds(0);
|
||||||
|
combined.setMilliseconds(0);
|
||||||
|
return combined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = async () => {
|
||||||
|
let finalStartDate: Date;
|
||||||
|
let finalEndDate: Date;
|
||||||
|
|
||||||
|
if (isAllDay) {
|
||||||
|
finalStartDate = new Date(startDate);
|
||||||
|
finalStartDate.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
finalEndDate = new Date(startDate);
|
||||||
|
finalEndDate.setHours(23, 59, 59, 999);
|
||||||
|
} else {
|
||||||
|
finalStartDate = combineDateAndTime(startDate, startTime);
|
||||||
|
finalEndDate = combineDateAndTime(endDate, endTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventData: Partial<EventData> = {
|
||||||
|
title,
|
||||||
|
startDate: finalStartDate,
|
||||||
|
endDate: finalEndDate,
|
||||||
|
repeatDays: repeatInterval.map(x => x.toString()),
|
||||||
|
allDay: isAllDay
|
||||||
|
};
|
||||||
|
|
||||||
|
await createEvent(eventData)
|
||||||
|
|
||||||
|
close();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRepeatLabel = () => {
|
||||||
|
const selectedDays = repeatInterval
|
||||||
|
const allDays = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
|
||||||
|
const workDays = ["monday", "tuesday", "wednesday", "thursday", "friday"];
|
||||||
|
|
||||||
|
const isEveryWorkDay = workDays.every(day => selectedDays.includes(day));
|
||||||
|
|
||||||
|
const isEveryDay = allDays.every(day => selectedDays.includes(day));
|
||||||
|
|
||||||
|
if (isEveryDay) {
|
||||||
|
return "Every day";
|
||||||
|
} else if (isEveryWorkDay && !selectedDays.includes("saturday") && !selectedDays.includes("sunday")) {
|
||||||
|
return "Every work day";
|
||||||
|
} else {
|
||||||
|
return selectedDays
|
||||||
|
.map(item => daysOfWeek.find(day => day.value === item)?.label)
|
||||||
|
.join(", ");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isLoading && !isError) {
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
visible={show}
|
||||||
|
animationType="slide"
|
||||||
|
onRequestClose={close}
|
||||||
|
transparent={false}
|
||||||
|
>
|
||||||
|
<LoaderScreen message={'Saving event...'} color={Colors.grey40}/>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
visible={show}
|
||||||
|
animationType="slide"
|
||||||
|
onRequestClose={close}
|
||||||
|
transparent={false}
|
||||||
|
>
|
||||||
|
<View style={{
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
paddingTop: insets.top, // Safe area inset for top
|
||||||
|
paddingBottom: insets.bottom, // Safe area inset for bottom
|
||||||
|
paddingLeft: insets.left, // Safe area inset for left
|
||||||
|
paddingRight: insets.right, // Safe area inset for right
|
||||||
|
}}>
|
||||||
|
<View style={{flexDirection: "row", justifyContent: "space-between", padding: 16}}>
|
||||||
|
<TouchableOpacity onPress={close}>
|
||||||
|
<Text style={{color: "#007bff"}}>Cancel</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<Text style={{fontWeight: "bold", fontSize: 16}}>Add event</Text>
|
||||||
|
<TouchableOpacity onPress={handleSave}>
|
||||||
|
<Text style={{color: "#007bff"}}>Save</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<ScrollView contentContainerStyle={{paddingHorizontal: 16, paddingTop: 10}}>
|
||||||
|
<View style={{marginVertical: 10}}>
|
||||||
|
<TextField
|
||||||
|
placeholder={'Title'}
|
||||||
|
floatingPlaceholder
|
||||||
|
value={title}
|
||||||
|
onChangeText={setTitle}
|
||||||
|
showCharCounter
|
||||||
|
maxLength={200}
|
||||||
|
fieldStyle={{
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: 'black',
|
||||||
|
borderStyle: 'solid',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={{
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
marginBottom: 20
|
||||||
|
}}>
|
||||||
|
<View style={{flexDirection: "row", alignItems: "center"}}>
|
||||||
|
<MaterialIcons name="schedule" size={24} color="gray"/>
|
||||||
|
<Text style={{marginLeft: 10}}>All-day</Text>
|
||||||
|
</View>
|
||||||
|
<Switch
|
||||||
|
value={isAllDay}
|
||||||
|
onValueChange={(value) => setIsAllDay(value)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={{
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
marginBottom: 20
|
||||||
|
}}>
|
||||||
|
<DateTimePicker
|
||||||
|
mode="date"
|
||||||
|
dateFormatter={formatDateTime}
|
||||||
|
value={startDate}
|
||||||
|
onChange={setStartDate}
|
||||||
|
/>
|
||||||
|
{!isAllDay && (
|
||||||
|
<DateTimePicker
|
||||||
|
mode="time"
|
||||||
|
value={startTime}
|
||||||
|
onChange={setStartTime}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{!isAllDay && (
|
||||||
|
<View style={{
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
marginBottom: 20
|
||||||
|
}}>
|
||||||
|
<DateTimePicker
|
||||||
|
mode="date"
|
||||||
|
dateFormatter={formatDateTime}
|
||||||
|
value={endDate}
|
||||||
|
onChange={setEndDate}
|
||||||
|
/>
|
||||||
|
<DateTimePicker
|
||||||
|
mode="time"
|
||||||
|
value={endTime}
|
||||||
|
onChange={setEndTime}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<View style={{flexDirection: "row", alignItems: "center", marginBottom: 20}}>
|
||||||
|
<MaterialIcons name="repeat" size={24} color="gray"/>
|
||||||
|
<Picker
|
||||||
|
value={repeatInterval}
|
||||||
|
//@ts-ignore
|
||||||
|
onChange={(items: PickerMultiValue) => setRepeatInterval(items)}
|
||||||
|
placeholder="Doest not repeat"
|
||||||
|
style={{marginLeft: 10, flex: 1}}
|
||||||
|
mode={Picker.modes.MULTI}
|
||||||
|
getLabel={getRepeatLabel}
|
||||||
|
|
||||||
|
>
|
||||||
|
{daysOfWeek.map((option) => (
|
||||||
|
<Picker.Item key={option.value} label={option.label} value={option.value}/>
|
||||||
|
))}
|
||||||
|
</Picker>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={{flexDirection: "row", alignItems: "center", marginBottom: 20}}>
|
||||||
|
<MaterialIcons name="person-add" size={24} color="gray"/>
|
||||||
|
<TouchableOpacity style={{marginLeft: 10, flexDirection: "row", alignItems: "center", flex: 1}}>
|
||||||
|
<Avatar size={40} backgroundColor={Colors.yellow10}/>
|
||||||
|
<View style={{marginLeft: 10}}>
|
||||||
|
<Text>Other</Text>
|
||||||
|
<Text style={{color: "gray"}}>{user?.email}</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
</View>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
@ -1,41 +1,49 @@
|
|||||||
import { View, Text, Button } from "react-native-ui-lib";
|
import { View, Text, Button, TextField } from "react-native-ui-lib";
|
||||||
import { TextInput } from "react-native";
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useSignIn } from "@/hooks/firebase/useSignIn";
|
import { useSignIn } from "@/hooks/firebase/useSignIn";
|
||||||
|
|
||||||
const SignInPage = (props: {
|
const SignInPage = (props: { setRegister: () => any }) => {
|
||||||
setRegister: () => any;
|
const [email, setEmail] = useState<string>("");
|
||||||
}) => {
|
const [password, setPassword] = useState<string>("");
|
||||||
const [email, setEmail] = useState<string>("");
|
|
||||||
const [password, setPassword] = useState<string>("");
|
|
||||||
|
|
||||||
const { mutateAsync: signIn } = useSignIn();
|
const { mutateAsync: signIn, error, isError } = useSignIn();
|
||||||
|
|
||||||
const handleSignIn = async () => {
|
const handleSignIn = async () => {
|
||||||
await signIn({email, password});
|
await signIn({ email, password });
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View marginH-20>
|
<View padding-10>
|
||||||
<TextInput placeholder="Email" value={email} onChangeText={setEmail} />
|
<TextField
|
||||||
<TextInput
|
placeholder="Email"
|
||||||
placeholder="Password"
|
value={email}
|
||||||
value={password}
|
onChangeText={setEmail}
|
||||||
onChangeText={setPassword}
|
style={{ marginBottom: 10 }}
|
||||||
secureTextEntry
|
floatingPlaceholder
|
||||||
/>
|
/>
|
||||||
<Button label="Login" onPress={handleSignIn} />
|
<TextField
|
||||||
<Text>Don't have an account?</Text>
|
placeholder="Password"
|
||||||
<Button
|
value={password}
|
||||||
onPress={props.setRegister}
|
onChangeText={setPassword}
|
||||||
label="Sign Up"
|
secureTextEntry
|
||||||
link
|
style={{ marginBottom: 10 }}
|
||||||
padding-0
|
floatingPlaceholder
|
||||||
margin-0
|
/>
|
||||||
left
|
<Button label="Login" onPress={handleSignIn} style={{ marginBottom: 20 }} />
|
||||||
/>
|
{isError && (
|
||||||
</View>
|
<Text center style={{ marginBottom: 20 }}>{`${error}`}</Text>
|
||||||
);
|
)}
|
||||||
|
<Text center style={{ marginBottom: 5 }}>Don't have an account?</Text>
|
||||||
|
<Button
|
||||||
|
onPress={props.setRegister}
|
||||||
|
label="Sign Up"
|
||||||
|
link
|
||||||
|
padding-0
|
||||||
|
margin-0
|
||||||
|
left
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SignInPage;
|
export default SignInPage;
|
||||||
|
@ -1,83 +1,96 @@
|
|||||||
import { TextInput } from "react-native";
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Checkbox, Button, View, Text } from "react-native-ui-lib";
|
import {Checkbox, Button, View, Text, TextField} from "react-native-ui-lib";
|
||||||
import { useSignUp } from "@/hooks/firebase/useSignUp";
|
import { useSignUp } from "@/hooks/firebase/useSignUp";
|
||||||
import { ProfileType } from "@/contexts/AuthContext";
|
import { ProfileType } from "@/contexts/AuthContext";
|
||||||
|
|
||||||
const SignUpPage = (props: { unsetRegister: () => any }) => {
|
const SignUpPage = (props: { unsetRegister: () => any }) => {
|
||||||
const [email, setEmail] = useState<string>("");
|
const [email, setEmail] = useState<string>("");
|
||||||
const [password, setPassword] = useState<string>("");
|
const [password, setPassword] = useState<string>("");
|
||||||
const [isParent, setIsParent] = useState<boolean>(true);
|
const [isParent, setIsParent] = useState<boolean>(true);
|
||||||
const [isChild, setIsChild] = useState<boolean>(false);
|
const [isChild, setIsChild] = useState<boolean>(false);
|
||||||
const [isCaregiver, setIsCaregiver] = useState<boolean>(false);
|
const [isCaregiver, setIsCaregiver] = useState<boolean>(false);
|
||||||
const [profileType, setProfileType] = useState<ProfileType>(
|
const [profileType, setProfileType] = useState<ProfileType>(
|
||||||
ProfileType.PARENT
|
ProfileType.PARENT
|
||||||
);
|
);
|
||||||
const { mutateAsync: signUp } = useSignUp();
|
const { mutateAsync: signUp } = useSignUp();
|
||||||
|
|
||||||
const handleSignUp = async () => {
|
const handleSignUp = async () => {
|
||||||
await signUp({ email, password });
|
await signUp({ email, password });
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View marginH-20>
|
<View padding-10>
|
||||||
<TextInput placeholder="Email" value={email} onChangeText={setEmail} />
|
<TextField
|
||||||
<TextInput
|
placeholder="Email"
|
||||||
placeholder="Password"
|
value={email}
|
||||||
value={password}
|
onChangeText={setEmail}
|
||||||
onChangeText={setPassword}
|
style={{ marginBottom: 10 }}
|
||||||
secureTextEntry
|
floatingPlaceholder
|
||||||
/>
|
/>
|
||||||
<Button label="Register" onPress={handleSignUp} />
|
<TextField
|
||||||
<Text>Choose Profile Type:</Text>
|
placeholder="Password"
|
||||||
<Checkbox
|
value={password}
|
||||||
label="Parent"
|
onChangeText={setPassword}
|
||||||
value={isParent}
|
secureTextEntry
|
||||||
onValueChange={(value) => {
|
style={{ marginBottom: 10 }}
|
||||||
setIsParent(value);
|
floatingPlaceholder
|
||||||
setProfileType(ProfileType.PARENT);
|
/>
|
||||||
if (value) {
|
<Button
|
||||||
setIsChild(false);
|
label="Register"
|
||||||
setIsCaregiver(false);
|
onPress={handleSignUp}
|
||||||
}
|
style={{ marginBottom: 10 }}
|
||||||
}}
|
/>
|
||||||
/>
|
<Text style={{ marginBottom: 10 }}>Choose Profile Type:</Text>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Child"
|
label="Parent"
|
||||||
value={isChild}
|
value={isParent}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
setIsChild(value);
|
setIsParent(value);
|
||||||
setProfileType(ProfileType.CHILD);
|
setProfileType(ProfileType.PARENT);
|
||||||
if (value) {
|
if (value) {
|
||||||
setIsParent(false);
|
setIsChild(false);
|
||||||
setIsCaregiver(false);
|
setIsCaregiver(false);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
style={{ marginBottom: 10 }}
|
||||||
<Checkbox
|
/>
|
||||||
label="Caregiver"
|
<Checkbox
|
||||||
value={isCaregiver}
|
label="Child"
|
||||||
onValueChange={(value) => {
|
value={isChild}
|
||||||
setIsCaregiver(value);
|
onValueChange={(value) => {
|
||||||
setProfileType(ProfileType.CAREGIVER);
|
setIsChild(value);
|
||||||
if (value) {
|
setProfileType(ProfileType.CHILD);
|
||||||
setIsParent(false);
|
if (value) {
|
||||||
setIsChild(false);
|
setIsParent(false);
|
||||||
}
|
setIsCaregiver(false);
|
||||||
}}
|
}
|
||||||
/>
|
}}
|
||||||
<Text>
|
style={{ marginBottom: 10 }}
|
||||||
Already have an account?
|
/>
|
||||||
<Button
|
<Checkbox
|
||||||
label="Sign In"
|
label="Caregiver"
|
||||||
margin-0
|
value={isCaregiver}
|
||||||
link
|
onValueChange={(value) => {
|
||||||
text200
|
setIsCaregiver(value);
|
||||||
onPress={props.unsetRegister}
|
setProfileType(ProfileType.CAREGIVER);
|
||||||
/>
|
if (value) {
|
||||||
</Text>
|
setIsParent(false);
|
||||||
</View>
|
setIsChild(false);
|
||||||
);
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Text center style={{ marginBottom: 5, marginTop: 10 }}>
|
||||||
|
Already have an account?
|
||||||
|
</Text>
|
||||||
|
<Button
|
||||||
|
label="Sign In"
|
||||||
|
margin-0
|
||||||
|
link
|
||||||
|
text200
|
||||||
|
onPress={props.unsetRegister}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SignUpPage;
|
export default SignUpPage;
|
||||||
|
@ -67,7 +67,7 @@ export const AuthContextProvider: FC<{ children: ReactNode }> = ({children}) =>
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ready && user) {
|
if (ready && user) {
|
||||||
replace({pathname: "/(auth)"})
|
replace({pathname: "/(auth)/calendar"})
|
||||||
} else if (ready && !user) {
|
} else if (ready && !user) {
|
||||||
replace({pathname: "/(unauth)"})
|
replace({pathname: "/(unauth)"})
|
||||||
}
|
}
|
||||||
|
13
hooks/firebase/types/eventData.ts
Normal file
13
hooks/firebase/types/eventData.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export interface EventData {
|
||||||
|
title: string,
|
||||||
|
startDate: Date,
|
||||||
|
endDate: Date,
|
||||||
|
allDay: boolean,
|
||||||
|
repeatDays: string[],
|
||||||
|
creatorId: string[],
|
||||||
|
userIds: string[],
|
||||||
|
timeZone?: string,
|
||||||
|
surpriseEvent?: boolean,
|
||||||
|
notes?: string,
|
||||||
|
reminders?: string[]
|
||||||
|
}
|
25
hooks/firebase/useCreateEvent.ts
Normal file
25
hooks/firebase/useCreateEvent.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
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 useCreateEvent = () => {
|
||||||
|
const {user: currentUser} = useAuthContext()
|
||||||
|
const queryClients = useQueryClient()
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationKey: ["createEvent"],
|
||||||
|
mutationFn: async (eventData: Partial<EventData>) => {
|
||||||
|
try {
|
||||||
|
await firestore()
|
||||||
|
.collection("Events")
|
||||||
|
.add({...eventData, creatorId: currentUser?.uid})
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClients.invalidateQueries("events")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
31
hooks/firebase/useGetEvents.ts
Normal file
31
hooks/firebase/useGetEvents.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import {useQuery} from "react-query";
|
||||||
|
import firestore from "@react-native-firebase/firestore";
|
||||||
|
import {ReactElement} from "react";
|
||||||
|
import {useAuthContext} from "@/contexts/AuthContext";
|
||||||
|
import {ICalendarEventBase} from "react-native-big-calendar";
|
||||||
|
|
||||||
|
export const useGetEvents = () => {
|
||||||
|
const {user} = useAuthContext()
|
||||||
|
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["events", user?.uid],
|
||||||
|
queryFn: async () => {
|
||||||
|
const snapshot = await firestore()
|
||||||
|
.collection("Events")
|
||||||
|
.where("creatorId", "==", user?.uid)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
const events: ICalendarEventBase[] = snapshot.docs.map((doc) => {
|
||||||
|
const data = doc.data();
|
||||||
|
return {
|
||||||
|
title: data.title,
|
||||||
|
start: new Date(data.startDate.seconds * 1000),
|
||||||
|
end: new Date(data.endDate.seconds * 1000),
|
||||||
|
hideHours: data.allDay,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -14,18 +14,12 @@ export const useUpdateUserData = () => {
|
|||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
try {
|
try {
|
||||||
console.log("yall don't even");
|
|
||||||
console.log(newUserData)
|
|
||||||
await firestore()
|
await firestore()
|
||||||
.collection("Profiles")
|
.collection("Profiles")
|
||||||
.doc(user.uid)
|
.doc(user.uid)
|
||||||
.set(newUserData);
|
.set(newUserData);
|
||||||
|
|
||||||
console.log("wtf")
|
|
||||||
const profileData = await firestore().collection("Profiles").doc(user?.uid!).get()
|
const profileData = await firestore().collection("Profiles").doc(user?.uid!).get()
|
||||||
console.log("wtf222")
|
|
||||||
|
|
||||||
console.log(profileData)
|
|
||||||
setProfileData(profileData.data() as UserProfile)
|
setProfileData(profileData.data() as UserProfile)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
|
@ -959,18 +959,18 @@ PODS:
|
|||||||
- EXJSONUtils (0.13.1)
|
- EXJSONUtils (0.13.1)
|
||||||
- EXManifests (0.14.3):
|
- EXManifests (0.14.3):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- Expo (51.0.29):
|
- Expo (51.0.30):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- expo-dev-client (4.0.23):
|
- expo-dev-client (4.0.24):
|
||||||
- EXManifests
|
- EXManifests
|
||||||
- expo-dev-launcher
|
- expo-dev-launcher
|
||||||
- expo-dev-menu
|
- expo-dev-menu
|
||||||
- expo-dev-menu-interface
|
- expo-dev-menu-interface
|
||||||
- EXUpdatesInterface
|
- EXUpdatesInterface
|
||||||
- expo-dev-launcher (4.0.25):
|
- expo-dev-launcher (4.0.26):
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
- EXManifests
|
- EXManifests
|
||||||
- expo-dev-launcher/Main (= 4.0.25)
|
- expo-dev-launcher/Main (= 4.0.26)
|
||||||
- expo-dev-menu
|
- expo-dev-menu
|
||||||
- expo-dev-menu-interface
|
- expo-dev-menu-interface
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
@ -996,7 +996,7 @@ PODS:
|
|||||||
- ReactCommon/turbomodule/bridging
|
- ReactCommon/turbomodule/bridging
|
||||||
- ReactCommon/turbomodule/core
|
- ReactCommon/turbomodule/core
|
||||||
- Yoga
|
- Yoga
|
||||||
- expo-dev-launcher/Main (4.0.25):
|
- expo-dev-launcher/Main (4.0.26):
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
- EXManifests
|
- EXManifests
|
||||||
- expo-dev-launcher/Unsafe
|
- expo-dev-launcher/Unsafe
|
||||||
@ -1025,7 +1025,7 @@ PODS:
|
|||||||
- ReactCommon/turbomodule/bridging
|
- ReactCommon/turbomodule/bridging
|
||||||
- ReactCommon/turbomodule/core
|
- ReactCommon/turbomodule/core
|
||||||
- Yoga
|
- Yoga
|
||||||
- expo-dev-launcher/Unsafe (4.0.25):
|
- expo-dev-launcher/Unsafe (4.0.26):
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
- EXManifests
|
- EXManifests
|
||||||
- expo-dev-menu
|
- expo-dev-menu
|
||||||
@ -1053,10 +1053,10 @@ PODS:
|
|||||||
- ReactCommon/turbomodule/bridging
|
- ReactCommon/turbomodule/bridging
|
||||||
- ReactCommon/turbomodule/core
|
- ReactCommon/turbomodule/core
|
||||||
- Yoga
|
- Yoga
|
||||||
- expo-dev-menu (5.0.19):
|
- expo-dev-menu (5.0.20):
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
- expo-dev-menu/Main (= 5.0.19)
|
- expo-dev-menu/Main (= 5.0.20)
|
||||||
- expo-dev-menu/ReactNativeCompatibles (= 5.0.19)
|
- expo-dev-menu/ReactNativeCompatibles (= 5.0.20)
|
||||||
- glog
|
- glog
|
||||||
- hermes-engine
|
- hermes-engine
|
||||||
- RCT-Folly (= 2024.01.01.00)
|
- RCT-Folly (= 2024.01.01.00)
|
||||||
@ -1077,7 +1077,7 @@ PODS:
|
|||||||
- ReactCommon/turbomodule/core
|
- ReactCommon/turbomodule/core
|
||||||
- Yoga
|
- Yoga
|
||||||
- expo-dev-menu-interface (1.8.3)
|
- expo-dev-menu-interface (1.8.3)
|
||||||
- expo-dev-menu/Main (5.0.19):
|
- expo-dev-menu/Main (5.0.20):
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
- EXManifests
|
- EXManifests
|
||||||
- expo-dev-menu-interface
|
- expo-dev-menu-interface
|
||||||
@ -1103,7 +1103,7 @@ PODS:
|
|||||||
- ReactCommon/turbomodule/bridging
|
- ReactCommon/turbomodule/bridging
|
||||||
- ReactCommon/turbomodule/core
|
- ReactCommon/turbomodule/core
|
||||||
- Yoga
|
- Yoga
|
||||||
- expo-dev-menu/ReactNativeCompatibles (5.0.19):
|
- expo-dev-menu/ReactNativeCompatibles (5.0.20):
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
- glog
|
- glog
|
||||||
- hermes-engine
|
- hermes-engine
|
||||||
@ -1124,7 +1124,7 @@ PODS:
|
|||||||
- ReactCommon/turbomodule/bridging
|
- ReactCommon/turbomodule/bridging
|
||||||
- ReactCommon/turbomodule/core
|
- ReactCommon/turbomodule/core
|
||||||
- Yoga
|
- Yoga
|
||||||
- expo-dev-menu/SafeAreaView (5.0.19):
|
- expo-dev-menu/SafeAreaView (5.0.20):
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- glog
|
- glog
|
||||||
@ -1146,7 +1146,7 @@ PODS:
|
|||||||
- ReactCommon/turbomodule/bridging
|
- ReactCommon/turbomodule/bridging
|
||||||
- ReactCommon/turbomodule/core
|
- ReactCommon/turbomodule/core
|
||||||
- Yoga
|
- Yoga
|
||||||
- expo-dev-menu/Vendored (5.0.19):
|
- expo-dev-menu/Vendored (5.0.20):
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
- expo-dev-menu/SafeAreaView
|
- expo-dev-menu/SafeAreaView
|
||||||
- glog
|
- glog
|
||||||
@ -1178,7 +1178,7 @@ PODS:
|
|||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- ExpoKeepAwake (13.0.2):
|
- ExpoKeepAwake (13.0.2):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- ExpoModulesCore (1.12.21):
|
- ExpoModulesCore (1.12.22):
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
- glog
|
- glog
|
||||||
- hermes-engine
|
- hermes-engine
|
||||||
@ -3009,17 +3009,17 @@ SPEC CHECKSUMS:
|
|||||||
EXConstants: 409690fbfd5afea964e5e9d6c4eb2c2b59222c59
|
EXConstants: 409690fbfd5afea964e5e9d6c4eb2c2b59222c59
|
||||||
EXJSONUtils: 30c17fd9cc364d722c0946a550dfbf1be92ef6a4
|
EXJSONUtils: 30c17fd9cc364d722c0946a550dfbf1be92ef6a4
|
||||||
EXManifests: c1fab4c3237675e7b0299ea8df0bcb14baca4f42
|
EXManifests: c1fab4c3237675e7b0299ea8df0bcb14baca4f42
|
||||||
Expo: 2c1f878fb356a11e8c32eb391f97eb7abfb21e55
|
Expo: 61b2953ad6afa979729f639c5992c182e8eb9040
|
||||||
expo-dev-client: 924e474dc9eccf507260a22c5a8301bed0497453
|
expo-dev-client: 44e9bb8afbf444bc380c606475030fe8929de203
|
||||||
expo-dev-launcher: 5f27c01458fd729684cc49a345f4c9ca052f4864
|
expo-dev-launcher: 012fd9aea425d902b5404e75e58d0bacf8e2542f
|
||||||
expo-dev-menu: 9ff772f6918e5fdfd73f31cc7534b853925f3d47
|
expo-dev-menu: 045ace71676316ecac9bff8c2ac34fa4d8ef8392
|
||||||
expo-dev-menu-interface: be32c09f1e03833050f0ee290dcc86b3ad0e73e4
|
expo-dev-menu-interface: be32c09f1e03833050f0ee290dcc86b3ad0e73e4
|
||||||
ExpoAsset: 323700f291684f110fb55f0d4022a3362ea9f875
|
ExpoAsset: 323700f291684f110fb55f0d4022a3362ea9f875
|
||||||
ExpoFileSystem: 80bfe850b1f9922c16905822ecbf97acd711dc51
|
ExpoFileSystem: 80bfe850b1f9922c16905822ecbf97acd711dc51
|
||||||
ExpoFont: e7f2275c10ca8573c991e007329ad6bf98086485
|
ExpoFont: e7f2275c10ca8573c991e007329ad6bf98086485
|
||||||
ExpoHead: fcb28a68ed4ba28f177394d2dfb8a0a8824cd103
|
ExpoHead: fcb28a68ed4ba28f177394d2dfb8a0a8824cd103
|
||||||
ExpoKeepAwake: 3b8815d9dd1d419ee474df004021c69fdd316d08
|
ExpoKeepAwake: 3b8815d9dd1d419ee474df004021c69fdd316d08
|
||||||
ExpoModulesCore: 620690a98d712d142e0acce5933419b05a63214a
|
ExpoModulesCore: 470e4a326c045a3b78c172e3e62d922e3df52a41
|
||||||
ExpoSystemUI: d4f065a016cae6721b324eb659cdee4d4cf0cb26
|
ExpoSystemUI: d4f065a016cae6721b324eb659cdee4d4cf0cb26
|
||||||
ExpoWebBrowser: 7595ccac6938eb65b076385fd23d035db9ecdc8e
|
ExpoWebBrowser: 7595ccac6938eb65b076385fd23d035db9ecdc8e
|
||||||
EXSplashScreen: d8b3c547b9b18a41d80c6f6b274c4c26664febd4
|
EXSplashScreen: d8b3c547b9b18a41d80c6f6b274c4c26664febd4
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-native": "0.74.3",
|
"react-native": "0.74.3",
|
||||||
|
"react-native-big-calendar": "^4.14.0",
|
||||||
"react-native-calendars": "^1.1306.0",
|
"react-native-calendars": "^1.1306.0",
|
||||||
"react-native-gesture-handler": "~2.16.1",
|
"react-native-gesture-handler": "~2.16.1",
|
||||||
"react-native-reanimated": "~3.10.1",
|
"react-native-reanimated": "~3.10.1",
|
||||||
|
Reference in New Issue
Block a user