mirror of
https://github.com/urosran/cally.git
synced 2025-08-26 06:09:40 +00:00
261 lines
9.8 KiB
TypeScript
261 lines
9.8 KiB
TypeScript
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>
|
|
);
|
|
};
|