Fix editing events

This commit is contained in:
Milan Paunovic
2024-10-20 15:32:30 +02:00
parent 5801420164
commit 8b37108be3
5 changed files with 81 additions and 330 deletions

View File

@ -1,303 +0,0 @@
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 ClockIcon from "@/assets/svgs/ClockIcon";
import LockIcon from "@/assets/svgs/LockIcon";
import MenuIcon from "@/assets/svgs/MenuIcon";
import {useUpdateEvent} from "@/hooks/firebase/useUpdateEvent";
import {editVisibleAtom, eventForEditAtom} from "@/components/pages/calendar/atoms";
import {useAtom} from "jotai";
const EditEventDialog = () => {
const [isVisible, setIsVisible] = useAtom(editVisibleAtom)
const [event, setEvent] = useAtom(eventForEditAtom)
const {mutateAsync: updateEvent} = useUpdateEvent();
if (!event) return null
return (
<Dialog
bottom={true}
height={"90%"}
panDirection={PanningDirectionsEnum.DOWN}
onDismiss={() => setIsVisible(false)}
containerStyle={{
borderRadius: 10,
backgroundColor: "white",
width: "100%",
alignSelf: "stretch",
padding: 0,
paddingTop: 4,
margin: 0,
}}
visible={isVisible}
>
<View row spread>
<Button
color="#05a8b6"
style={styles.topBtn}
label="Cancel"
onPress={() => {
setIsVisible(false);
}}
/>
<View marginT-12>
<DropModalIcon
onPress={() => {
setIsVisible(false);
}}
/>
</View>
<Button
color="#05a8b6"
style={styles.topBtn}
label="Save"
onPress={() => {
try {
if (event.id) {
updateEvent(event).then(() => setIsVisible(false));
}
} catch (error) {
console.error(error);
}
}}
/>
</View>
<TextField
placeholder="Edit event title"
value={event.title}
onChangeText={(text) => {
setEvent((prevEvent) => ({
...prevEvent!,
title: text,
}));
}}
placeholderTextColor="#2d2d30"
text60R
marginT-15
marginL-30
/>
<View style={styles.divider} marginT-8/>
<View row spread marginB-10 marginL-30 centerV>
<View row>
<AntDesign name="clockcircleo" size={24} color="#919191"/>
<Text text70 marginL-10>
All day
</Text>
</View>
<View right marginR-30>
<Switch
onColor={"#ea156c"}
offColor={"#e1e1e2"}
marginL-10
value={event.allDay}
onValueChange={(value) =>
setEvent((prev) => ({...prev!, allDay: value}))
}
/>
</View>
</View>
<View marginL-30 centerV>
<View row marginB-10 spread>
<View row centerV>
<Feather name="calendar" size={25} color="#919191"/>
<DateTimePicker
value={event.start}
text70
marginL-8
maximumDate={event.end}
onChange={(date) => {
setEvent((prev) => ({...prev!, start: date}));
}}
/>
</View>
<DateTimePicker
text70
value={event.start}
onChange={(date) => {
setEvent((prev) => ({...prev!, start: date}));
}}
maximumDate={event.end}
dateTimeFormatter={(date) => date.toLocaleTimeString("en-us",
{
hour: "numeric",
minute: "numeric"
})}
mode="time"
marginR-30
/>
</View>
{!event.allDay && (
<View row marginB-10 spread>
<View row centerV>
<Feather name="calendar" size={25} color="#919191"/>
<DateTimePicker
value={event.end}
minimumDate={event.start}
text70
marginL-8
onChange={(date) => {
setEvent((prev) => ({...prev!, end: date}));
}}
/>
</View>
<DateTimePicker
text70
value={event.end}
minimumDate={event.start}
onChange={(date) => {
setEvent((prev) => ({...prev!, end: date}));
}}
dateTimeFormatter={(date) => date.toLocaleTimeString("en-us",
{
hour: "numeric",
minute: "numeric"
})}
mode="time"
marginR-30
/>
</View>
)}
</View>
<View style={styles.divider}/>
<View marginH-30 marginB-10 row centerV>
<Ionicons name="person-circle-outline" size={28} color="#919191"/>
<Text text70R marginL-10>
Assignees
</Text>
<Button
size={ButtonSize.small}
paddingH-8
iconSource={() => (
<Ionicons name="add-outline" size={20} color="#ea156c"/>
)}
style={{
marginLeft: "auto",
borderRadius: 8,
backgroundColor: "#ffe8f1",
borderColor: "#ea156c",
borderWidth: 1,
}}
color="#ea156c"
label="Assign"
/>
</View>
<View row marginH-13 marginT-13>
<View
marginL-30
style={{
aspectRatio: 1,
width: 50,
backgroundColor: "red",
borderRadius: 50,
}}
/>
<View
marginL-30
style={{
aspectRatio: 1,
width: 50,
backgroundColor: "red",
borderRadius: 50,
}}
/>
</View>
<View style={styles.divider}/>
<View marginH-30 marginB-0 row spread centerV>
<View row centerV>
<ClockIcon/>
<Text text70 marginL-10>
Reminder
</Text>
</View>
<View>
<Button
size={ButtonSize.small}
paddingH-8
iconSource={() => (
<Ionicons name="add-outline" size={20} color="#ea156c"/>
)}
style={{
marginLeft: "auto",
borderRadius: 8,
backgroundColor: "#ffe8f1",
borderColor: "#ea156c",
borderWidth: 1,
}}
color="#ea156c"
label="Set Reminder"
/>
</View>
</View>
<View style={styles.divider}/>
<View marginH-30 marginB-0 row spread centerV>
<View row>
<LockIcon/>
<Text text70 marginL-10>
Mark as Private
</Text>
</View>
<View>
<Switch
onColor={"#ea156c"}
offColor={"#e1e1e2"}
marginL-10
value={event.private}
onValueChange={(value) =>
setEvent((prev) => ({...prev!, private: value}))
}
/>
</View>
</View>
<View style={styles.divider}/>
<View marginH-30 marginB-0 row spread centerV>
<View row centerV>
<MenuIcon/>
<Text text70 marginL-10>
Add Details
</Text>
</View>
<View></View>
</View>
</Dialog>
);
};
export default EditEventDialog;
const styles = StyleSheet.create({
divider: {height: 1, backgroundColor: "#e4e4e4", marginVertical: 15},
gradient: {
height: "25%",
position: "absolute",
bottom: 0,
width: "100%",
},
buttonContainer: {
position: "absolute",
bottom: 25,
width: "100%",
},
button: {
backgroundColor: "rgb(253, 23, 117)",
paddingVertical: 20,
},
topBtn: {
backgroundColor: "white",
color: "#05a8b6",
},
rotateSwitch: {
marginLeft: 35,
marginBottom: 10,
marginTop: 25,
},
});

View File

@ -48,9 +48,14 @@ export const EventCalendar: React.FC<EventCalendarProps> = React.memo(({calendar
}, [events, mode]); }, [events, mode]);
const handlePressEvent = useCallback((event: CalendarEvent) => { const handlePressEvent = useCallback((event: CalendarEvent) => {
if (mode === "day") {
setEditVisible(true); setEditVisible(true);
setEventForEdit(event); setEventForEdit(event);
}, [setEditVisible, setEventForEdit]); } else {
setMode("day")
setSelectedDate(event.start);
}
}, [setEditVisible, setEventForEdit, mode]);
const handlePressCell = useCallback( const handlePressCell = useCallback(
(date: Date) => { (date: Date) => {

View File

@ -3,7 +3,6 @@ import React, {useRef, useState} from "react";
import {LayoutChangeEvent} from "react-native"; import {LayoutChangeEvent} from "react-native";
import CalendarViewSwitch from "@/components/pages/calendar/CalendarViewSwitch"; import CalendarViewSwitch from "@/components/pages/calendar/CalendarViewSwitch";
import {AddEventDialog} from "@/components/pages/calendar/AddEventDialog"; import {AddEventDialog} from "@/components/pages/calendar/AddEventDialog";
import EditEventDialog from "@/components/pages/calendar/EditEventDialog";
import {ManuallyAddEventModal} from "@/components/pages/calendar/ManuallyAddEventModal"; import {ManuallyAddEventModal} from "@/components/pages/calendar/ManuallyAddEventModal";
import {CalendarHeader} from "@/components/pages/calendar/CalendarHeader"; import {CalendarHeader} from "@/components/pages/calendar/CalendarHeader";
import {EventCalendar} from "@/components/pages/calendar/EventCalendar"; import {EventCalendar} from "@/components/pages/calendar/EventCalendar";
@ -37,7 +36,6 @@ export const InnerCalendar = () => {
<CalendarViewSwitch/> <CalendarViewSwitch/>
<AddEventDialog/> <AddEventDialog/>
<EditEventDialog/>
<ManuallyAddEventModal/> <ManuallyAddEventModal/>
</> </>
) )

View File

@ -15,7 +15,7 @@ import {
} from "react-native-ui-lib"; } from "react-native-ui-lib";
import {ScrollView} from "react-native-gesture-handler"; import {ScrollView} from "react-native-gesture-handler";
import {useSafeAreaInsets} from "react-native-safe-area-context"; import {useSafeAreaInsets} from "react-native-safe-area-context";
import {useState} from "react"; import {useEffect, useState} from "react";
import {AntDesign, Feather, Ionicons,} from "@expo/vector-icons"; import {AntDesign, Feather, Ionicons,} from "@expo/vector-icons";
import {PickerMultiValue} from "react-native-ui-lib/src/components/picker/types"; import {PickerMultiValue} from "react-native-ui-lib/src/components/picker/types";
import {useCreateEvent} from "@/hooks/firebase/useCreateEvent"; import {useCreateEvent} from "@/hooks/firebase/useCreateEvent";
@ -29,7 +29,7 @@ import MenuIcon from "@/assets/svgs/MenuIcon";
import CameraIcon from "@/assets/svgs/CameraIcon"; import CameraIcon from "@/assets/svgs/CameraIcon";
import AssigneesDisplay from "@/components/shared/AssigneesDisplay"; import AssigneesDisplay from "@/components/shared/AssigneesDisplay";
import {useAtom} from "jotai"; import {useAtom} from "jotai";
import {selectedNewEventDateAtom} from "@/components/pages/calendar/atoms"; import {eventForEditAtom, selectedNewEventDateAtom} from "@/components/pages/calendar/atoms";
import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers"; import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers";
const daysOfWeek = [ const daysOfWeek = [
@ -46,42 +46,73 @@ export const ManuallyAddEventModal = () => {
const insets = useSafeAreaInsets(); const insets = useSafeAreaInsets();
const [selectedNewEventDate, setSelectedNewEndDate] = useAtom(selectedNewEventDateAtom) const [selectedNewEventDate, setSelectedNewEndDate] = useAtom(selectedNewEventDateAtom)
const [editEvent, setEditEvent] = useAtom(eventForEditAtom)
const {show, close, initialDate} = { const { show, close, initialDate } = {
show: !!selectedNewEventDate, show: !!selectedNewEventDate || !!editEvent,
close: () => setSelectedNewEndDate(undefined), close: () => {
initialDate: selectedNewEventDate setSelectedNewEndDate(undefined)
setEditEvent(undefined)
},
initialDate: selectedNewEventDate || editEvent?.start
} }
const [title, setTitle] = useState<string>(""); const [title, setTitle] = useState<string>(editEvent?.title || "");
const [isAllDay, setIsAllDay] = useState(editEvent?.allDay || false);
const [isAllDay, setIsAllDay] = useState(false); const [isPrivate, setIsPrivate] = useState<boolean>(editEvent?.private || false);
const [isPrivate, setIsPrivate] = useState<boolean>(false);
const [startTime, setStartTime] = useState(() => { const [startTime, setStartTime] = useState(() => {
const date = initialDate ?? new Date(); const date = initialDate ?? new Date();
date.setSeconds(0, 0); date.setSeconds(0, 0);
return date; return date;
}); });
const [endTime, setEndTime] = useState(() => { const [endTime, setEndTime] = useState(() => {
const date = initialDate if (editEvent?.end) {
? addHours(initialDate, 1) const date = new Date(editEvent.end);
date.setSeconds(0, 0);
return date;
}
const date = (editEvent?.end ?? initialDate)
? addHours((editEvent?.end ?? initialDate!), 1)
: addHours(new Date(), 1); : addHours(new Date(), 1);
date.setSeconds(0, 0); date.setSeconds(0, 0);
return date; return date;
}); });
const [startDate, setStartDate] = useState(initialDate ?? new Date()); const [startDate, setStartDate] = useState(initialDate ?? new Date());
const [endDate, setEndDate] = useState(initialDate ?? new Date()); const [endDate, setEndDate] = useState(editEvent?.end ?? initialDate ?? new Date());
const [selectedAttendees, setSelectedAttendees] = useState<string[]>(editEvent?.participants ?? []);
const [selectedAttendees, setSelectedAttendees] = useState<string[]>([]);
const [repeatInterval, setRepeatInterval] = useState<PickerMultiValue>([]); const [repeatInterval, setRepeatInterval] = useState<PickerMultiValue>([]);
const {mutateAsync: createEvent, isLoading, isError} = useCreateEvent(); const { mutateAsync: createEvent, isLoading, isError } = useCreateEvent();
const {data: members} = useGetFamilyMembers(true) const { data: members } = useGetFamilyMembers(true);
useEffect(() => {
setTitle(editEvent?.title || "");
setIsAllDay(editEvent?.allDay || false);
setIsPrivate(editEvent?.private || false);
setStartTime(() => {
const date = initialDate ?? new Date();
date.setSeconds(0, 0);
return date;
});
setEndTime(() => {
if (editEvent?.end) {
const date = new Date(editEvent.end);
date.setSeconds(0, 0);
return date;
}
const date = (editEvent?.end ?? initialDate)
? addHours((editEvent?.end ?? initialDate!), 1)
: addHours(new Date(), 1);
date.setSeconds(0, 0);
return date;
});
setStartDate(initialDate ?? new Date());
setEndDate(editEvent?.end ?? initialDate ?? new Date());
setSelectedAttendees(editEvent?.participants ?? []);
setRepeatInterval([]);
}, [editEvent, selectedNewEventDate]);
if (!selectedNewEventDate) return null; if (!show) return null;
const formatDateTime = (date?: Date | string) => { const formatDateTime = (date?: Date | string) => {
if (!date) return undefined; if (!date) return undefined;
@ -119,6 +150,7 @@ export const ManuallyAddEventModal = () => {
endDate: finalEndDate, endDate: finalEndDate,
allDay: isAllDay, allDay: isAllDay,
attendees: selectedAttendees, attendees: selectedAttendees,
id: editEvent?.id
}; };
await createEvent(eventData); await createEvent(eventData);

View File

@ -11,11 +11,30 @@ export const useCreateEvent = () => {
mutationKey: ["createEvent"], mutationKey: ["createEvent"],
mutationFn: async (eventData: Partial<EventData>) => { mutationFn: async (eventData: Partial<EventData>) => {
try { try {
if (eventData.id) {
const snapshot = await firestore()
.collection("Events")
.where("id", "==", eventData.id)
.get();
if (!snapshot.empty) {
const docId = snapshot.docs[0].id;
await firestore() await firestore()
.collection("Events") .collection("Events")
.add({...eventData, creatorId: currentUser?.uid, familyId: profileData?.familyId}) .doc(docId)
.set({
...eventData,
creatorId: currentUser?.uid,
familyId: profileData?.familyId
}, {merge: true});
return;
}
}
await firestore()
.collection("Events")
.add({...eventData, creatorId: currentUser?.uid, familyId: profileData?.familyId});
} catch (e) { } catch (e) {
console.error(e) console.error(e);
} }
}, },
onSuccess: () => { onSuccess: () => {