added confirmation dialogs, fixed scroll wheels ui tweaks

This commit is contained in:
ivic00
2024-10-30 00:02:25 +01:00
parent 74d82e2029
commit 7f79a1c819
14 changed files with 1077 additions and 654 deletions

View File

@ -26,6 +26,7 @@ import NavSettingsIcon from "@/assets/svgs/NavSettingsIcon";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { import {
settingsPageIndex, settingsPageIndex,
toDosPageIndex,
userSettingsView, userSettingsView,
} from "@/components/pages/calendar/atoms"; } from "@/components/pages/calendar/atoms";
@ -33,6 +34,7 @@ export default function TabLayout() {
const { mutateAsync: signOut } = useSignOut(); const { mutateAsync: signOut } = useSignOut();
const [pageIndex, setPageIndex] = useAtom(settingsPageIndex); const [pageIndex, setPageIndex] = useAtom(settingsPageIndex);
const [userView, setUserView] = useAtom(userSettingsView); const [userView, setUserView] = useAtom(userSettingsView);
const [toDosIndex, setToDosIndex] = useAtom(toDosPageIndex);
return ( return (
<Drawer <Drawer
@ -76,6 +78,7 @@ export default function TabLayout() {
pressFunc={() => { pressFunc={() => {
props.navigation.navigate("calendar"); props.navigation.navigate("calendar");
setPageIndex(0); setPageIndex(0);
setToDosIndex(0);
setUserView(true); setUserView(true);
}} }}
icon={<NavCalendarIcon />} icon={<NavCalendarIcon />}
@ -87,6 +90,7 @@ export default function TabLayout() {
pressFunc={() => { pressFunc={() => {
props.navigation.navigate("grocery"); props.navigation.navigate("grocery");
setPageIndex(0); setPageIndex(0);
setToDosIndex(0);
setUserView(true); setUserView(true);
}} }}
icon={<NavGroceryIcon />} icon={<NavGroceryIcon />}
@ -113,6 +117,7 @@ export default function TabLayout() {
pressFunc={() => { pressFunc={() => {
props.navigation.navigate("todos"); props.navigation.navigate("todos");
setPageIndex(0); setPageIndex(0);
setToDosIndex(0);
setUserView(true); setUserView(true);
}} }}
icon={<NavToDosIcon />} icon={<NavToDosIcon />}
@ -124,6 +129,7 @@ export default function TabLayout() {
pressFunc={() => { pressFunc={() => {
props.navigation.navigate("brain_dump"); props.navigation.navigate("brain_dump");
setPageIndex(0); setPageIndex(0);
setToDosIndex(0);
setUserView(true); setUserView(true);
}} }}
icon={<NavBrainDumpIcon />} icon={<NavBrainDumpIcon />}
@ -135,6 +141,7 @@ export default function TabLayout() {
onPress={() => { onPress={() => {
props.navigation.navigate("settings"); props.navigation.navigate("settings");
setPageIndex(0); setPageIndex(0);
setToDosIndex(0);
setUserView(true); setUserView(true);
}} }}
label={"Manage Settings"} label={"Manage Settings"}

View File

@ -3,8 +3,8 @@ import Svg, { Path, LinearGradient, Stop, SvgProps } from "react-native-svg";
const OutlookIcon: React.FC<SvgProps> = (props) => ( const OutlookIcon: React.FC<SvgProps> = (props) => (
<Svg <Svg
width={34} width={props.width || 34}
height={34} height={props.height || 34}
viewBox="0 0 48 48" viewBox="0 0 48 48"
{...props} {...props}
> >

View File

@ -0,0 +1,82 @@
import React from "react";
import { Dialog, Button, Text, View } from "react-native-ui-lib";
import { StyleSheet } from "react-native";
interface BrainDumpDialogProps {
visible: boolean;
title: string;
onDismiss: () => void;
onConfirm: () => void;
}
const BrainDumpDialog: React.FC<BrainDumpDialogProps> = ({
visible,
title,
onDismiss,
onConfirm,
}) => {
return (
<Dialog
visible={visible}
onDismiss={onDismiss}
containerStyle={styles.dialog}
>
<Text center style={styles.title}>
Delete Note
</Text>
<View center>
<Text style={styles.text} center>
Are you sure you want to delete the {"\n"}
<Text style={{ fontSize: 16, fontFamily: "PlusJakartaSans_700Bold" }}>
{title}
</Text>{" "}
Note?
</Text>
</View>
<View row right gap-8>
<Button
label="Cancel"
onPress={onDismiss}
style={styles.cancelBtn}
color="#999999"
labelStyle={{ fontFamily: "Poppins_500Medium", fontSize: 13.53 }}
/>
<Button
label="Yes"
onPress={onConfirm}
style={styles.confirmBtn}
labelStyle={{ fontFamily: "PlusJakartaSans_500Medium" }}
/>
</View>
</Dialog>
);
};
// Empty stylesheet for future styles
const styles = StyleSheet.create({
confirmBtn: {
backgroundColor: "#ea156d",
},
cancelBtn: {
backgroundColor: "white",
},
dialog: {
backgroundColor: "white",
paddingHorizontal: 25,
paddingTop: 35,
paddingBottom: 17,
borderRadius: 20,
},
title: {
fontFamily: "Manrope_600SemiBold",
fontSize: 22,
marginBottom: 20,
},
text: {
fontFamily: "PlusJakartaSans_400Regular",
fontSize: 16,
marginBottom: 25,
},
});
export default BrainDumpDialog;

View File

@ -18,6 +18,7 @@ import NavCalendarIcon from "@/assets/svgs/NavCalendarIcon";
import NavToDosIcon from "@/assets/svgs/NavToDosIcon"; import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
import RemindersIcon from "@/assets/svgs/RemindersIcon"; import RemindersIcon from "@/assets/svgs/RemindersIcon";
import MenuIcon from "@/assets/svgs/MenuIcon"; import MenuIcon from "@/assets/svgs/MenuIcon";
import BrainDumpDialog from "./BrainDumpDialog";
const MoveBrainDump = (props: { const MoveBrainDump = (props: {
item: IBrainDump; item: IBrainDump;
@ -28,12 +29,26 @@ const MoveBrainDump = (props: {
const [description, setDescription] = useState<string>( const [description, setDescription] = useState<string>(
props.item.description props.item.description
); );
const [modalVisible, setModalVisible] = useState<boolean>(false);
const { width } = Dimensions.get("screen"); const { width } = Dimensions.get("screen");
useEffect(() => { useEffect(() => {
updateBrainDumpItem(props.item.id, { description: description }); updateBrainDumpItem(props.item.id, { description: description });
}, [description]); }, [description]);
const showConfirmationDialog = () => {
setModalVisible(true);
};
const handleDeleteNote = () =>{
deleteBrainDump(props.item.id);
}
const hideConfirmationDialog = () => {
setModalVisible(false);
}
return ( return (
<Dialog <Dialog
bottom={true} bottom={true}
@ -81,8 +96,7 @@ const MoveBrainDump = (props: {
marginL-5 marginL-5
iconSource={() => <BinIcon />} iconSource={() => <BinIcon />}
onPress={() => { onPress={() => {
deleteBrainDump(props.item.id); showConfirmationDialog();
props.setIsVisible(false);
}} }}
/> />
</View> </View>
@ -145,6 +159,7 @@ const MoveBrainDump = (props: {
</View> </View>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<BrainDumpDialog visible={modalVisible} title={props.item.title} onDismiss={hideConfirmationDialog} onConfirm={handleDeleteNote} />
</Dialog> </Dialog>
); );
}; };
@ -191,10 +206,10 @@ const styles = StyleSheet.create({
fontSize: 22, fontSize: 22,
fontFamily: "Manrope_500Medium", fontFamily: "Manrope_500Medium",
}, },
description:{ description: {
fontFamily: "Manrope_400Regular", fontFamily: "Manrope_400Regular",
fontSize: 14, fontSize: 14,
} },
}); });
export default MoveBrainDump; export default MoveBrainDump;

View File

@ -0,0 +1,81 @@
import React from "react";
import { Dialog, Button, Text, View } from "react-native-ui-lib";
import { StyleSheet } from "react-native";
interface DeleteEventDialogProps {
visible: boolean;
title: string;
onDismiss: () => void;
onConfirm: () => void;
}
const DeleteEventDialog: React.FC<DeleteEventDialogProps> = ({
visible,
title,
onDismiss,
onConfirm,
}) => {
return (
<Dialog
visible={visible}
onDismiss={onDismiss}
containerStyle={styles.dialog}
>
<Text center style={styles.title}>
Delete Event
</Text>
<View center>
<Text style={styles.text} center>
Are you sure you want to delete the event:{" "}
<Text style={{ fontSize: 16, fontFamily: "PlusJakartaSans_700Bold" }}>
{title}
</Text>{" "}
</Text>
</View>
<View row right gap-8>
<Button
label="Cancel"
onPress={onDismiss}
style={styles.cancelBtn}
color="#999999"
labelStyle={{ fontFamily: "Poppins_500Medium", fontSize: 13.53 }}
/>
<Button
label="Yes"
onPress={onConfirm}
style={styles.confirmBtn}
labelStyle={{ fontFamily: "PlusJakartaSans_500Medium" }}
/>
</View>
</Dialog>
);
};
// Empty stylesheet for future styles
const styles = StyleSheet.create({
confirmBtn: {
backgroundColor: "#ea156d",
},
cancelBtn: {
backgroundColor: "white",
},
dialog: {
backgroundColor: "white",
paddingHorizontal: 25,
paddingTop: 35,
paddingBottom: 17,
borderRadius: 20,
},
title: {
fontFamily: "Manrope_600SemiBold",
fontSize: 22,
marginBottom: 20,
},
text: {
fontFamily: "PlusJakartaSans_400Regular",
fontSize: 16,
marginBottom: 25,
},
});
export default DeleteEventDialog;

View File

@ -207,7 +207,7 @@ export const EventCalendar: React.FC<EventCalendarProps> = React.memo(
scrollOffsetMinutes={offsetMinutes} scrollOffsetMinutes={offsetMinutes}
theme={{ theme={{
palette: { palette: {
nowIndicator: "#fd1575", nowIndicator: profileData?.eventColor || "#fd1575",
gray: { gray: {
"100": "#e8eaed", "100": "#e8eaed",
"200": "#e8eaed", "200": "#e8eaed",
@ -223,13 +223,15 @@ export const EventCalendar: React.FC<EventCalendarProps> = React.memo(
fontSize: 16, fontSize: 16,
}, },
moreLabel: {}, moreLabel: {},
xs:{fontSize: 10} xs: { fontSize: 10 },
}, },
}} }}
dayHeaderStyle={dateStyle} dayHeaderStyle={dateStyle}
dayHeaderHighlightColor={"white"} dayHeaderHighlightColor={"white"}
renderCustomDateForMonth={renderCustomDateForMonth} renderCustomDateForMonth={renderCustomDateForMonth}
showAdjacentMonths showAdjacentMonths
hourStyle={styles.hourStyle}
ampm
/> />
); );
} }
@ -273,4 +275,9 @@ const styles = StyleSheet.create({
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",
}, },
hourStyle: {
color: "#5f6368",
fontSize: 12,
fontFamily: "Manrope_500Medium",
},
}); });

View File

@ -14,56 +14,78 @@ import {
TouchableOpacity, TouchableOpacity,
View, View,
} 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 {useEffect, useRef, useState} from "react"; import { useEffect, useRef, 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";
import {EventData} from "@/hooks/firebase/types/eventData"; import { EventData } from "@/hooks/firebase/types/eventData";
import {addHours} from "date-fns"; import { addHours } from "date-fns";
import DropModalIcon from "@/assets/svgs/DropModalIcon"; import DropModalIcon from "@/assets/svgs/DropModalIcon";
import {StyleSheet} from "react-native"; import { StyleSheet } from "react-native";
import ClockIcon from "@/assets/svgs/ClockIcon"; import ClockIcon from "@/assets/svgs/ClockIcon";
import LockIcon from "@/assets/svgs/LockIcon"; import LockIcon from "@/assets/svgs/LockIcon";
import MenuIcon from "@/assets/svgs/MenuIcon"; 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 {eventForEditAtom, selectedNewEventDateAtom} from "@/components/pages/calendar/atoms"; import {
import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers"; eventForEditAtom,
selectedNewEventDateAtom,
} from "@/components/pages/calendar/atoms";
import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers";
import BinIcon from "@/assets/svgs/BinIcon";
import CloseXIcon from "@/assets/svgs/CloseXIcon";
import PenIcon from "@/assets/svgs/PenIcon";
import DeleteEventDialog from "./DeleteEventDialog";
const daysOfWeek = [ const daysOfWeek = [
{label: "Monday", value: "monday"}, { label: "Monday", value: "monday" },
{label: "Tuesday", value: "tuesday"}, { label: "Tuesday", value: "tuesday" },
{label: "Wednesday", value: "wednesday"}, { label: "Wednesday", value: "wednesday" },
{label: "Thursday", value: "thursday"}, { label: "Thursday", value: "thursday" },
{label: "Friday", value: "friday"}, { label: "Friday", value: "friday" },
{label: "Saturday", value: "saturday"}, { label: "Saturday", value: "saturday" },
{label: "Sunday", value: "sunday"}, { label: "Sunday", value: "sunday" },
]; ];
export const ManuallyAddEventModal = () => { export const ManuallyAddEventModal = () => {
const insets = useSafeAreaInsets(); const insets = useSafeAreaInsets();
const [selectedNewEventDate, setSelectedNewEndDate] = useAtom(selectedNewEventDateAtom) const [selectedNewEventDate, setSelectedNewEndDate] = useAtom(
const [editEvent, setEditEvent] = useAtom(eventForEditAtom) selectedNewEventDateAtom
);
const [editEvent, setEditEvent] = useAtom(eventForEditAtom);
const [deleteModalVisible, setDeleteModalVisible] = useState<boolean>(false);
const {show, close, initialDate} = { const showDeleteEventModal = () => {
setDeleteModalVisible(true);
};
const handleDeleteEvent = () => {};
const hideDeleteEventModal = () => {
setDeleteModalVisible(false);
};
const { show, close, initialDate } = {
show: !!selectedNewEventDate || !!editEvent, show: !!selectedNewEventDate || !!editEvent,
close: () => { close: () => {
setSelectedNewEndDate(undefined) setSelectedNewEndDate(undefined);
setEditEvent(undefined) setEditEvent(undefined);
}, },
initialDate: selectedNewEventDate || editEvent?.start initialDate: selectedNewEventDate || editEvent?.start,
} };
const detailsRef = useRef<TextFieldRef>(null) const detailsRef = useRef<TextFieldRef>(null);
const [title, setTitle] = useState<string>(editEvent?.title || ""); const [title, setTitle] = useState<string>(editEvent?.title || "");
const [details, setDetails] = useState<string>(editEvent?.notes || ""); const [details, setDetails] = useState<string>(editEvent?.notes || "");
const [isAllDay, setIsAllDay] = useState(editEvent?.allDay || false); const [isAllDay, setIsAllDay] = useState(editEvent?.allDay || false);
const [isPrivate, setIsPrivate] = useState<boolean>(editEvent?.private || false); const [isPrivate, setIsPrivate] = useState<boolean>(
editEvent?.private || 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);
@ -75,19 +97,24 @@ export const ManuallyAddEventModal = () => {
date.setSeconds(0, 0); date.setSeconds(0, 0);
return date; return date;
} }
const date = (editEvent?.end ?? initialDate) const date =
? addHours((editEvent?.end ?? initialDate!), 1) 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(editEvent?.end ?? initialDate ?? new Date()); const [endDate, setEndDate] = useState(
const [selectedAttendees, setSelectedAttendees] = useState<string[]>(editEvent?.participants ?? []); editEvent?.end ?? initialDate ?? new Date()
);
const [selectedAttendees, setSelectedAttendees] = useState<string[]>(
editEvent?.participants ?? []
);
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(() => { useEffect(() => {
setTitle(editEvent?.title || ""); setTitle(editEvent?.title || "");
@ -105,8 +132,9 @@ export const ManuallyAddEventModal = () => {
date.setSeconds(0, 0); date.setSeconds(0, 0);
return date; return date;
} }
const date = (editEvent?.end ?? initialDate) const date =
? addHours((editEvent?.end ?? initialDate!), 1) 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;
@ -155,13 +183,13 @@ export const ManuallyAddEventModal = () => {
endDate: finalEndDate, endDate: finalEndDate,
allDay: isAllDay, allDay: isAllDay,
attendees: selectedAttendees, attendees: selectedAttendees,
notes: details notes: details,
}; };
if (editEvent?.id) eventData.id = editEvent?.id if (editEvent?.id) eventData.id = editEvent?.id;
await createEvent(eventData); await createEvent(eventData);
setEditEvent(undefined) setEditEvent(undefined);
close(); close();
}; };
@ -206,7 +234,7 @@ export const ManuallyAddEventModal = () => {
onRequestClose={close} onRequestClose={close}
transparent={false} transparent={false}
> >
<LoaderScreen message={"Saving event..."} color={Colors.grey40}/> <LoaderScreen message={"Saving event..."} color={Colors.grey40} />
</Modal> </Modal>
); );
} }
@ -228,6 +256,39 @@ export const ManuallyAddEventModal = () => {
paddingRight: insets.right, // Safe area inset for right paddingRight: insets.right, // Safe area inset for right
}} }}
> >
{editEvent ? (
<>
<View center paddingT-8>
<TouchableOpacity onPress={close}>
<DropModalIcon />
</TouchableOpacity>
</View>
<View row spread paddingH-10 paddingB-15>
<Button
color="#05a8b6"
style={styles.topBtn}
iconSource={() => <CloseXIcon />}
onPress={close}
/>
<View row>
<Button
style={styles.topBtn}
marginR-10
iconSource={() => <PenIcon />}
onPress={handleSave}
/>
<Button
style={styles.topBtn}
marginL-5
iconSource={() => <BinIcon />}
onPress={() => {
showDeleteEventModal();
}}
/>
</View>
</View>
</>
) : (
<View <View
style={{ style={{
flexDirection: "row", flexDirection: "row",
@ -247,7 +308,7 @@ export const ManuallyAddEventModal = () => {
Cancel Cancel
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
<DropModalIcon onPress={close}/> <DropModalIcon onPress={close} />
<TouchableOpacity onPress={handleSave}> <TouchableOpacity onPress={handleSave}>
<Text <Text
style={{ style={{
@ -261,7 +322,8 @@ export const ManuallyAddEventModal = () => {
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<ScrollView style={{minHeight: "85%"}}> )}
<ScrollView style={{ minHeight: "85%" }}>
<TextField <TextField
placeholder="Add event title" placeholder="Add event title"
value={title} value={title}
@ -270,16 +332,16 @@ export const ManuallyAddEventModal = () => {
setTitle(text); setTitle(text);
}} }}
placeholderTextColor="#2d2d30" placeholderTextColor="#2d2d30"
style={{fontFamily: "Manrope_500Medium", fontSize: 22}} style={{ fontFamily: "Manrope_500Medium", fontSize: 22 }}
paddingT-15 paddingT-15
paddingL-30 paddingL-30
returnKeyType="next" returnKeyType="next"
/> />
<View style={styles.divider} marginT-8/> <View style={styles.divider} marginT-8 />
<View marginL-30 centerV> <View marginL-30 centerV>
<View row spread marginB-10 centerV> <View row spread marginB-10 centerV>
<View row> <View row>
<AntDesign name="clockcircleo" size={24} color="#919191"/> <AntDesign name="clockcircleo" size={24} color="#919191" />
<Text <Text
style={{ style={{
fontFamily: "PlusJakartaSans_500Medium", fontFamily: "PlusJakartaSans_500Medium",
@ -302,13 +364,13 @@ export const ManuallyAddEventModal = () => {
</View> </View>
<View row marginB-10 spread> <View row marginB-10 spread>
<View row centerV> <View row centerV>
<Feather name="calendar" size={25} color="#919191"/> <Feather name="calendar" size={25} color="#919191" />
<DateTimePicker <DateTimePicker
value={startDate} value={startDate}
onChange={(date) => { onChange={(date) => {
setStartDate(date); setStartDate(date);
}} }}
maximumDate={endDate} //maximumDate={endDate}
style={{ style={{
fontFamily: "PlusJakartaSans_500Medium", fontFamily: "PlusJakartaSans_500Medium",
fontSize: 16, fontSize: 16,
@ -320,7 +382,7 @@ export const ManuallyAddEventModal = () => {
value={startTime} value={startTime}
onChange={(time) => { onChange={(time) => {
if (time <= endTime) { if (time <= endTime) {
setStartTime(time) setStartTime(time);
} else { } else {
const currentTime = new Date(); const currentTime = new Date();
currentTime.setSeconds(0, 0); currentTime.setSeconds(0, 0);
@ -346,7 +408,7 @@ export const ManuallyAddEventModal = () => {
{!isAllDay && ( {!isAllDay && (
<View row marginB-10 spread> <View row marginB-10 spread>
<View row centerV> <View row centerV>
<Feather name="calendar" size={25} color="#919191"/> <Feather name="calendar" size={25} color="#919191" />
<DateTimePicker <DateTimePicker
value={endDate} value={endDate}
minimumDate={startDate} minimumDate={startDate}
@ -391,28 +453,30 @@ export const ManuallyAddEventModal = () => {
)} )}
</View> </View>
<View style={styles.divider}/> <View style={styles.divider} />
<View marginH-30 marginB-10 row centerV> <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 <Text
style={{fontFamily: "Manrope_600SemiBold", fontSize: 18}} style={{ fontFamily: "Manrope_600SemiBold", fontSize: 18 }}
marginL-10 marginL-10
> >
Attendees Attendees
</Text> </Text>
<View flex-1/> <View flex-1 />
<Picker <Picker
value={selectedAttendees} value={selectedAttendees}
onChange={(value) => setSelectedAttendees(value as string[] ?? [])} onChange={(value) =>
style={{marginLeft: "auto"}} setSelectedAttendees((value as string[]) ?? [])
}
style={{ marginLeft: "auto" }}
mode={PickerModes.MULTI} mode={PickerModes.MULTI}
renderInput={() => renderInput={() => (
<Button <Button
size={ButtonSize.small} size={ButtonSize.small}
paddingH-8 paddingH-8
iconSource={() => ( iconSource={() => (
<Ionicons name="add-outline" size={20} color="#ea156c"/> <Ionicons name="add-outline" size={20} color="#ea156c" />
)} )}
style={{ style={{
marginLeft: "auto", marginLeft: "auto",
@ -423,9 +487,13 @@ export const ManuallyAddEventModal = () => {
}} }}
color="#ea156c" color="#ea156c"
label="Add" label="Add"
labelStyle={{fontFamily: "Manrope_600SemiBold", fontSize: 14}} labelStyle={{
fontFamily: "Manrope_600SemiBold",
fontSize: 14,
}}
/> />
}> )}
>
{members?.map((member) => ( {members?.map((member) => (
<Picker.Item <Picker.Item
key={member?.uid} key={member?.uid}
@ -437,14 +505,16 @@ export const ManuallyAddEventModal = () => {
</View> </View>
<View marginL-35> <View marginL-35>
<AssigneesDisplay setSelectedAttendees={setSelectedAttendees} <AssigneesDisplay
selectedAttendees={selectedAttendees}/> setSelectedAttendees={setSelectedAttendees}
selectedAttendees={selectedAttendees}
/>
</View> </View>
<View style={styles.divider}/> <View style={styles.divider} />
<View marginH-30 marginB-0 row spread centerV> <View marginH-30 marginB-0 row spread centerV>
<View row centerV> <View row centerV>
<ClockIcon/> <ClockIcon />
<Text <Text
style={{ style={{
fontFamily: "Manrope_600SemiBold", fontFamily: "Manrope_600SemiBold",
@ -460,7 +530,7 @@ export const ManuallyAddEventModal = () => {
size={ButtonSize.small} size={ButtonSize.small}
paddingH-8 paddingH-8
iconSource={() => ( iconSource={() => (
<Ionicons name="add-outline" size={20} color="#ea156c"/> <Ionicons name="add-outline" size={20} color="#ea156c" />
)} )}
style={{ style={{
marginLeft: "auto", marginLeft: "auto",
@ -469,16 +539,16 @@ export const ManuallyAddEventModal = () => {
borderColor: "#ea156c", borderColor: "#ea156c",
borderWidth: 1, borderWidth: 1,
}} }}
labelStyle={{fontFamily: "Manrope_600SemiBold", fontSize: 14}} labelStyle={{ fontFamily: "Manrope_600SemiBold", fontSize: 14 }}
color="#ea156c" color="#ea156c"
label="Set Reminder" label="Set Reminder"
/> />
</View> </View>
</View> </View>
<View style={styles.divider}/> <View style={styles.divider} />
<View marginH-30 marginB-0 row spread centerV> <View marginH-30 marginB-0 row spread centerV>
<View row centerH> <View row centerH>
<LockIcon/> <LockIcon />
<Text <Text
style={{ style={{
fontFamily: "PlusJakartaSans_500Medium", fontFamily: "PlusJakartaSans_500Medium",
@ -499,11 +569,11 @@ export const ManuallyAddEventModal = () => {
/> />
</View> </View>
</View> </View>
<View style={styles.divider}/> <View style={styles.divider} />
<View marginH-30 marginB-0 spread centerV flex-1> <View marginH-30 marginB-0 spread centerV flex-1>
<TouchableOpacity onPress={() => detailsRef?.current?.focus()}> <TouchableOpacity onPress={() => detailsRef?.current?.focus()}>
<View row centerV> <View row centerV>
<MenuIcon/> <MenuIcon />
<Text <Text
style={{ style={{
fontFamily: "PlusJakartaSans_500Medium", fontFamily: "PlusJakartaSans_500Medium",
@ -516,8 +586,16 @@ export const ManuallyAddEventModal = () => {
</View> </View>
</TouchableOpacity> </TouchableOpacity>
<TextField value={details} onChangeText={setDetails} ref={detailsRef} maxLength={2000} multiline <TextField
numberOfLines={10} marginT-10 style={{flex: 1, minHeight: 180}}/> value={details}
onChangeText={setDetails}
ref={detailsRef}
maxLength={2000}
multiline
numberOfLines={10}
marginT-10
style={{ flex: 1, minHeight: 180 }}
/>
</View> </View>
</ScrollView> </ScrollView>
<Button <Button
@ -526,22 +604,30 @@ export const ManuallyAddEventModal = () => {
marginB-15 marginB-15
label="Create event from image" label="Create event from image"
text70 text70
style={{height: 47}} style={{ height: 47 }}
labelStyle={{fontFamily: "PlusJakartaSans_500Medium", fontSize: 15}} labelStyle={{ fontFamily: "PlusJakartaSans_500Medium", fontSize: 15 }}
backgroundColor="#05a8b6" backgroundColor="#05a8b6"
iconSource={() => ( iconSource={() => (
<View marginR-5> <View marginR-5>
<CameraIcon color="white"/> <CameraIcon color="white" />
</View> </View>
)} )}
/> />
</View> </View>
{editEvent && (
<DeleteEventDialog
visible={deleteModalVisible}
title={editEvent?.title}
onDismiss={hideDeleteEventModal}
onConfirm={handleDeleteEvent}
/>
)}
</Modal> </Modal>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
divider: {height: 1, backgroundColor: "#e4e4e4", marginVertical: 15}, divider: { height: 1, backgroundColor: "#e4e4e4", marginVertical: 15 },
gradient: { gradient: {
height: "25%", height: "25%",
position: "absolute", position: "absolute",

View File

@ -9,3 +9,4 @@ export const selectedDateAtom = atom<Date>(new Date());
export const selectedNewEventDateAtom = atom<Date | undefined>(undefined); export const selectedNewEventDateAtom = atom<Date | undefined>(undefined);
export const settingsPageIndex = atom<number>(0); export const settingsPageIndex = atom<number>(0);
export const userSettingsView = atom<boolean>(true); export const userSettingsView = atom<boolean>(true);
export const toDosPageIndex = atom<number>(0);

View File

@ -14,7 +14,7 @@ const AddGroceryItem = () => {
paddingH-25 paddingH-25
style={{ style={{
position: "absolute", position: "absolute",
bottom: 20, bottom: 65,
width: "100%", width: "100%",
height: 60, height: 60,
}} }}

View File

@ -1,12 +1,12 @@
import {ScrollView} from "react-native"; import { Dimensions, ScrollView } from "react-native";
import {View} from "react-native-ui-lib"; import { View } from "react-native-ui-lib";
import React, {useEffect, useRef} from "react"; import React, { useEffect, useRef } from "react";
import AddGroceryItem from "./AddGroceryItem"; import AddGroceryItem from "./AddGroceryItem";
import GroceryList from "./GroceryList"; import GroceryList from "./GroceryList";
import {useGroceryContext} from "@/contexts/GroceryContext"; import { useGroceryContext } from "@/contexts/GroceryContext";
const GroceryWrapper = () => { const GroceryWrapper = () => {
const {isAddingGrocery} = useGroceryContext(); const { isAddingGrocery } = useGroceryContext();
const scrollViewRef = useRef<ScrollView>(null); // Reference to the ScrollView const scrollViewRef = useRef<ScrollView>(null); // Reference to the ScrollView
useEffect(() => { useEffect(() => {
@ -19,18 +19,22 @@ const GroceryWrapper = () => {
}, [isAddingGrocery]); }, [isAddingGrocery]);
return ( return (
<View height={"100%"} paddingT-15 paddingH-15> <View height={Dimensions.get("window").height}>
<View height={"100%"}> <View>
<ScrollView <ScrollView
ref={scrollViewRef} ref={scrollViewRef}
automaticallyAdjustKeyboardInsets={true} automaticallyAdjustKeyboardInsets={true}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
> >
<View marginB-70> <View height={"100%"}>
<GroceryList/> <View marginB-115>
<GroceryList />
</View>
</View> </View>
</ScrollView> </ScrollView>
{!isAddingGrocery && <AddGroceryItem/>}
</View> </View>
{!isAddingGrocery && <AddGroceryItem />}
</View> </View>
); );
}; };

View File

@ -1,7 +1,7 @@
import { AntDesign, Ionicons } from "@expo/vector-icons"; import { AntDesign, Ionicons } from "@expo/vector-icons";
import React, { useCallback, useEffect, useState } from "react"; import React, { useCallback, useEffect, useState } from "react";
import { Button, Checkbox, Text, View } from "react-native-ui-lib"; import { Button, Checkbox, Text, View } from "react-native-ui-lib";
import { ActivityIndicator, ScrollView, StyleSheet } from "react-native"; import { ActivityIndicator, Alert, ScrollView, StyleSheet } from "react-native";
import { TouchableOpacity } from "react-native-gesture-handler"; import { TouchableOpacity } from "react-native-gesture-handler";
import { useAuthContext } from "@/contexts/AuthContext"; import { useAuthContext } from "@/contexts/AuthContext";
import { useUpdateUserData } from "@/hooks/firebase/useUpdateUserData"; import { useUpdateUserData } from "@/hooks/firebase/useUpdateUserData";
@ -21,6 +21,7 @@ import ExpoLocalization from "expo-localization/src/ExpoLocalization";
import { colorMap } from "@/constants/colorMap"; import { colorMap } from "@/constants/colorMap";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { settingsPageIndex } from "../calendar/atoms"; import { settingsPageIndex } from "../calendar/atoms";
import CalendarSettingsDialog from "./calendar_components/CalendarSettingsDialog";
const googleConfig = { const googleConfig = {
androidClientId: androidClientId:
@ -61,6 +62,29 @@ const CalendarSettingsPage = () => {
? "Mondays" ? "Mondays"
: "Sundays" : "Sundays"
); );
const [isModalVisible, setModalVisible] = useState<boolean>(false);
const [selectedService, setSelectedService] = useState<
"google" | "outlook" | "apple"
>("google");
const [selectedEmail, setSelectedEmail] = useState<string>("");
const showConfirmationDialog = (
serviceName: "google" | "outlook" | "apple",
email: string
) => {
setSelectedService(serviceName);
setSelectedEmail(email);
setModalVisible(true);
};
const handleConfirm = () => {
clearToken(selectedService, selectedEmail);
setModalVisible(false);
};
const handleCancel = () => {
setModalVisible(false);
};
const [selectedColor, setSelectedColor] = useState<string>( const [selectedColor, setSelectedColor] = useState<string>(
profileData?.eventColor ?? colorMap.pink profileData?.eventColor ?? colorMap.pink
@ -477,7 +501,9 @@ const CalendarSettingsPage = () => {
googleToken && ( googleToken && (
<Button <Button
key={googleMail} key={googleMail}
onPress={() => clearToken("google", googleMail)} onPress={() => {
showConfirmationDialog("google", googleMail);
}}
label={`Disconnect ${googleMail}`} label={`Disconnect ${googleMail}`}
labelStyle={styles.addCalLbl} labelStyle={styles.addCalLbl}
labelProps={{ labelProps={{
@ -520,7 +546,7 @@ const CalendarSettingsPage = () => {
appleToken && ( appleToken && (
<Button <Button
key={appleEmail} key={appleEmail}
onPress={() => clearToken("apple", appleEmail)} onPress={() => showConfirmationDialog("apple", appleEmail)}
label={`Disconnect ${appleEmail}`} label={`Disconnect ${appleEmail}`}
labelStyle={styles.addCalLbl} labelStyle={styles.addCalLbl}
labelProps={{ labelProps={{
@ -565,7 +591,9 @@ const CalendarSettingsPage = () => {
microsoftToken && ( microsoftToken && (
<Button <Button
key={microsoftEmail} key={microsoftEmail}
onPress={() => clearToken("outlook", microsoftEmail)} onPress={() => {
showConfirmationDialog("outlook", microsoftEmail);
}}
label={`Disconnect ${microsoftEmail}`} label={`Disconnect ${microsoftEmail}`}
labelStyle={styles.addCalLbl} labelStyle={styles.addCalLbl}
labelProps={{ labelProps={{
@ -754,6 +782,13 @@ const CalendarSettingsPage = () => {
</> </>
)} )}
</View> </View>
<CalendarSettingsDialog
visible={isModalVisible}
serviceName={selectedService}
email={selectedEmail}
onDismiss={handleCancel}
onConfirm={handleConfirm}
/>
</ScrollView> </ScrollView>
); );
}; };

View File

@ -0,0 +1,86 @@
import React from "react";
import { Dialog, Button, Text, View } from "react-native-ui-lib";
import { StyleSheet } from "react-native";
interface ConfirmationDialogProps {
visible: boolean;
serviceName: "google" | "outlook" | "apple";
email: string;
onDismiss: () => void;
onConfirm: () => void;
}
const CalendarSettingsDialog: React.FC<ConfirmationDialogProps> = ({
visible,
serviceName,
email,
onDismiss,
onConfirm,
}) => {
return (
<Dialog
visible={visible}
onDismiss={onDismiss}
containerStyle={styles.dialog}
>
<Text center style={styles.title}>
Disconnect {serviceName}
</Text>
<View center>
<Text style={styles.text} center>
Are you sure you want to disconnect this {"\n"}
<Text style={{ fontSize: 16, fontFamily: "PlusJakartaSans_700Bold" }}>
{serviceName}
</Text>{" "}
calendar
{"\n"}
for {email}?
</Text>
</View>
<View row right gap-8>
<Button
label="Cancel"
onPress={onDismiss}
style={styles.cancelBtn}
color="#999999"
labelStyle={{ fontFamily: "Poppins_500Medium", fontSize: 13.53 }}
/>
<Button
label="Yes"
onPress={onConfirm}
style={styles.confirmBtn}
labelStyle={{ fontFamily: "PlusJakartaSans_500Medium" }}
/>
</View>
</Dialog>
);
};
// Empty stylesheet for future styles
const styles = StyleSheet.create({
confirmBtn: {
backgroundColor: "#ea156d",
},
cancelBtn: {
backgroundColor: "white",
},
dialog: {
backgroundColor: "white",
paddingHorizontal: 25,
paddingTop: 35,
paddingBottom: 17,
borderRadius: 20,
},
title: {
fontFamily: "Manrope_600SemiBold",
fontSize: 22,
marginBottom: 20,
},
text: {
fontFamily: "PlusJakartaSans_400Regular",
fontSize: 16,
marginBottom: 25,
},
});
export default CalendarSettingsDialog;

View File

@ -12,11 +12,11 @@ import { useToDosContext } from "@/contexts/ToDosContext";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import PointsSlider from "@/components/shared/PointsSlider"; import PointsSlider from "@/components/shared/PointsSlider";
import { IToDo } from "@/hooks/firebase/types/todoData"; import { IToDo } from "@/hooks/firebase/types/todoData";
import { ImageBackground } from "react-native"; import { ImageBackground, StyleSheet } from "react-native";
import AddChoreDialog from "@/components/pages/todos/AddChoreDialog"; import AddChoreDialog from "@/components/pages/todos/AddChoreDialog";
import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers"; import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers";
import RepeatIcon from "@/assets/svgs/RepeatIcon"; import RepeatIcon from "@/assets/svgs/RepeatIcon";
import {ProfileType, useAuthContext} from "@/contexts/AuthContext"; import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => { const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
const { updateToDo } = useToDosContext(); const { updateToDo } = useToDosContext();
@ -48,7 +48,7 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
let isTodoEditable; let isTodoEditable;
if (isParent) { if (isParent) {
isTodoEditable = true isTodoEditable = true;
} else { } else {
isTodoEditable = props.item.creatorId === profileData?.uid; isTodoEditable = props.item.creatorId === profileData?.uid;
} }
@ -81,20 +81,16 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
fontSize: 15, fontSize: 15,
}} }}
onPress={() => { onPress={() => {
isTodoEditable ? setVisible(true) : null isTodoEditable ? setVisible(true) : null;
}} }}
> >
{props.item.title} {props.item.title}
</Text> </Text>
<Checkbox <Checkbox
value={props.item.done} value={props.item.done}
containerStyle={{ containerStyle={[styles.checkbox, { borderRadius: 50 }]}
borderWidth: 0.7, style={styles.checked}
borderRadius: 50, borderRadius={50}
borderColor: "gray",
height: 24.64,
width: 24.64,
}}
color="#fd1575" color="#fd1575"
onValueChange={(value) => { onValueChange={(value) => {
updateToDo({ id: props.item.id, done: !props.item.done }); updateToDo({ id: props.item.id, done: !props.item.done });
@ -258,3 +254,17 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
}; };
export default ToDoItem; export default ToDoItem;
const styles = StyleSheet.create({
checkbox: {
borderRadius: 50,
borderWidth: 0.7,
color: "#bfbfbf",
borderColor: "#bfbfbf",
width: 24.64,
aspectRatio: 1,
},
checked: {
borderRadius: 50,
},
});

View File

@ -1,35 +1,43 @@
import {Button, Text, View} from "react-native-ui-lib"; import { Button, Text, View } from "react-native-ui-lib";
import React, {useState} from "react"; import React, { useState } from "react";
import HeaderTemplate from "@/components/shared/HeaderTemplate"; import HeaderTemplate from "@/components/shared/HeaderTemplate";
import AddChore from "./AddChore"; import AddChore from "./AddChore";
import ProgressCard from "./ProgressCard"; import ProgressCard from "./ProgressCard";
import ToDosList from "./ToDosList"; import ToDosList from "./ToDosList";
import {Dimensions, ScrollView, StyleSheet} from "react-native"; import { Dimensions, ScrollView, StyleSheet } from "react-native";
import {TouchableOpacity} from "react-native-gesture-handler"; import { TouchableOpacity } from "react-native-gesture-handler";
import {ProfileType, useAuthContext} from "@/contexts/AuthContext"; import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
import FamilyChoresProgress from "./family-chores/FamilyChoresProgress"; import FamilyChoresProgress from "./family-chores/FamilyChoresProgress";
import UserChoresProgress from "./user-chores/UserChoresProgress"; import UserChoresProgress from "./user-chores/UserChoresProgress";
import { useAtom } from "jotai";
import { toDosPageIndex } from "../calendar/atoms";
const ToDosPage = () => { const ToDosPage = () => {
const [pageIndex, setPageIndex] = useState<number>(0); const { profileData } = useAuthContext();
const {profileData} = useAuthContext(); const [pageIndex, setPageIndex] = useAtom(toDosPageIndex);
const {width, height} = Dimensions.get("screen");
const { width, height } = Dimensions.get("screen");
const pageLink = ( const pageLink = (
<TouchableOpacity onPress={() => setPageIndex(1)}> <TouchableOpacity onPress={() => setPageIndex(1)}>
<Text color="#ea156d" style={{fontSize: 14}}> <Text color="#ea156d" style={{ fontSize: 14 }}>
View family progress View family progress
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
); );
return ( return (
<> <>
<View paddingH-25 backgroundColor="#f9f8f7" height={"100%"} width={width}>
{pageIndex == 0 && (
<View>
<ScrollView <ScrollView
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false} showsHorizontalScrollIndicator={false}
> >
<View
paddingH-25
backgroundColor="#f9f8f7"
height={"100%"}
width={width}
>
{pageIndex == 0 && (
<View>
<View> <View>
<HeaderTemplate <HeaderTemplate
message="Here are your To Do's" message="Here are your To Do's"
@ -57,18 +65,19 @@ const ToDosPage = () => {
/> />
</View> </View>
)} )}
<ToDosList/> <ToDosList />
</View> </View>
</ScrollView>
</View> </View>
)} )}
{pageIndex == 1 && <FamilyChoresProgress setPageIndex={setPageIndex}/>} {pageIndex == 1 && (
{pageIndex == 2 && <UserChoresProgress setPageIndex={setPageIndex}/>} <FamilyChoresProgress setPageIndex={setPageIndex} />
)}
{pageIndex == 2 && <UserChoresProgress setPageIndex={setPageIndex} />}
</View> </View>
<AddChore/> </ScrollView>
<AddChore />
</> </>
) );
;
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({