Merge branch 'dev' into tablet

This commit is contained in:
ivic00
2024-11-03 17:10:12 +01:00
102 changed files with 9637 additions and 2793 deletions

View File

@ -6,8 +6,8 @@ import {
DrawerItem,
DrawerItemList,
} from "@react-navigation/drawer";
import { Button, View, Text, ButtonSize, Constants } from "react-native-ui-lib";
import { StyleSheet } from "react-native";
import { Button, View, Text, ButtonSize } from "react-native-ui-lib";
import { Dimensions, ImageBackground, StyleSheet } from "react-native";
import Feather from "@expo/vector-icons/Feather";
import DrawerButton from "@/components/shared/DrawerButton";
import {
@ -24,9 +24,21 @@ import NavBrainDumpIcon from "@/assets/svgs/NavBrainDumpIcon";
import NavCalendarIcon from "@/assets/svgs/NavCalendarIcon";
import NavSettingsIcon from "@/assets/svgs/NavSettingsIcon";
import ViewSwitch from "@/components/pages/(tablet_pages)/ViewSwitch";
import { useAtom, useSetAtom } from "jotai";
import {
isFamilyViewAtom,
settingsPageIndex,
toDosPageIndex,
userSettingsView,
} from "@/components/pages/calendar/atoms";
import FeedbackNavIcon from "@/assets/svgs/FeedbackNavIcon";
export default function TabLayout() {
const { mutateAsync: signOut } = useSignOut();
const setIsFamilyView = useSetAtom(isFamilyViewAtom);
const setPageIndex = useSetAtom(settingsPageIndex);
const setUserView = useSetAtom(userSettingsView);
const setToDosIndex = useSetAtom(toDosPageIndex);
return (
<Drawer
@ -45,12 +57,20 @@ export default function TabLayout() {
backgroundColor: "#f9f8f7",
height: "100%",
},
drawerIcon: () => <MenuIcon />,
}}
drawerContent={(props) => {
return (
<DrawerContentScrollView {...props} style={{ height: "100%" }}>
<View centerH centerV margin-30>
<DrawerContentScrollView {...props} style={{}}>
<View centerV marginH-30 marginT-20 marginB-20 row>
<ImageBackground
source={require("../../assets/images/splash.png")}
style={{
backgroundColor: "transparent",
height: 51.43,
aspectRatio: 1,
marginRight: 8,
}}
/>
<Text style={styles.title}>Welcome to Cally</Text>
</View>
<View
@ -64,16 +84,41 @@ export default function TabLayout() {
title={"Calendar"}
color="rgb(7, 184, 199)"
bgColor={"rgb(231, 248, 250)"}
pressFunc={() => props.navigation.navigate("calendar")}
pressFunc={() => {
props.navigation.navigate("calendar");
setPageIndex(0);
setToDosIndex(0);
setUserView(true);
setIsFamilyView(false);
}}
icon={<NavCalendarIcon />}
/>
<DrawerButton
color="#50be0c"
title={"Groceries"}
bgColor={"#eef9e7"}
pressFunc={() => props.navigation.navigate("grocery")}
pressFunc={() => {
props.navigation.navigate("grocery");
setPageIndex(0);
setToDosIndex(0);
setUserView(true);
setIsFamilyView(false);
}}
icon={<NavGroceryIcon />}
/>
<DrawerButton
color="#ea156d"
title={"Feedback"}
bgColor={"#fdedf4"}
pressFunc={() => {
props.navigation.navigate("feedback");
setPageIndex(0);
setToDosIndex(0);
setUserView(true);
setIsFamilyView(false);
}}
icon={<FeedbackNavIcon />}
/>
</View>
<View style={{ flex: 1 }}>
{/*<DrawerButton
@ -93,21 +138,39 @@ export default function TabLayout() {
color="#8005eb"
title={"To Do's"}
bgColor={"#f3e6fd"}
pressFunc={() => props.navigation.navigate("todos")}
pressFunc={() => {
props.navigation.navigate("todos");
setPageIndex(0);
setToDosIndex(0);
setUserView(true);
setIsFamilyView(false);
}}
icon={<NavToDosIcon />}
/>
<DrawerButton
color="#e0ca03"
title={"Brain Dump"}
bgColor={"#fffacb"}
pressFunc={() => props.navigation.navigate("brain_dump")}
pressFunc={() => {
props.navigation.navigate("brain_dump");
setPageIndex(0);
setToDosIndex(0);
setUserView(true);
setIsFamilyView(false);
}}
icon={<NavBrainDumpIcon />}
/>
{/*<DrawerItem label="Logout" onPress={() => signOut()} />*/}
</View>
</View>
<Button
onPress={() => props.navigation.navigate("settings")}
onPress={() => {
props.navigation.navigate("settings");
setPageIndex(0);
setToDosIndex(0);
setUserView(true);
setIsFamilyView(false);
}}
label={"Manage Settings"}
labelStyle={styles.label}
iconSource={() => (
@ -135,9 +198,9 @@ export default function TabLayout() {
<Button
size={ButtonSize.large}
marginH-30
marginT-12
paddingV-15
style={{
marginTop: "42%",
backgroundColor: "transparent",
borderWidth: 1.3,
borderColor: "#fd1775",
@ -198,9 +261,13 @@ export default function TabLayout() {
name="todos"
options={{
drawerLabel: "To-Do",
title: "To-Do's",
title: "To-Dos",
}}
/>
<Drawer.Screen
name="feedback"
options={{ drawerLabel: "Feedback", title: "Feedback" }}
/>
</Drawer>
);
}

View File

@ -0,0 +1,5 @@
import {Stack} from "expo-router";
export default function StackLayout () {
return <Stack screenOptions={{headerShown: false}}/>
}

View File

@ -0,0 +1,13 @@
import FeedbackPage from "@/components/pages/feedback/FeedbackPage";
import { FeedbackProvider } from "@/contexts/FeedbackContext";
import { View } from "react-native-ui-lib";
export default function Screen() {
return (
<FeedbackProvider>
<View>
<FeedbackPage />
</View>
</FeedbackProvider>
);
}

246
app/(unauth)/cal_sync.tsx Normal file
View File

@ -0,0 +1,246 @@
import {SafeAreaView} from "react-native-safe-area-context";
import {Button, Text, View} from "react-native-ui-lib";
import React from "react";
import {useCalSync} from "@/hooks/useCalSync";
import GoogleIcon from "@/assets/svgs/GoogleIcon";
import AppleIcon from "@/assets/svgs/AppleIcon";
import OutlookIcon from "@/assets/svgs/OutlookIcon";
import {useAuthContext} from "@/contexts/AuthContext";
import {StyleSheet} from "react-native";
export default function Screen() {
const {profileData, setRedirectOverride} = useAuthContext()
const {handleStartGoogleSignIn, handleAppleSignIn, handleMicrosoftSignIn} = useCalSync()
const hasSomeCalendarsSynced =
!!profileData?.appleAccounts || !!profileData?.microsoftAccounts || !!profileData?.googleAccounts
return (
<SafeAreaView style={{flex: 1}}>
<View style={{flex: 1, padding: 21, paddingBottom: 45, paddingTop: "20%", alignItems: "center"}}>
<View gap-13 width={"100%"} marginB-20>
<Text style={{fontSize: 40, fontFamily: 'Manrope_600SemiBold'}}>
Let's get started!
</Text>
<Text color={"#919191"} style={{fontSize: 20}}>
Add your calendar below to sync events to your Cally calendar
</Text>
</View>
<View width={"100%"} gap-1>
{!profileData?.googleAccounts && (
<Button
onPress={() => handleStartGoogleSignIn()}
label={"Connect Google account"}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<GoogleIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
)}
{profileData?.googleAccounts
? Object.keys(profileData?.googleAccounts)?.map((googleMail) => {
const googleToken = profileData?.googleAccounts?.[googleMail]?.accessToken;
return (
googleToken && (
<Button
key={googleMail}
disabled
label={`Connected ${googleMail}`}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<GoogleIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
)
);
})
: null}
{!profileData?.appleAccounts && (
<Button
onPress={() => handleAppleSignIn()}
label={"Connect Apple"}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<AppleIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
)}
{profileData?.appleAccounts
? Object.keys(profileData?.appleAccounts)?.map((appleEmail) => {
const appleToken = profileData?.appleAccounts?.[appleEmail!];
return (
appleToken && (
<Button
key={appleEmail}
disabled
label={`Connected Apple Calendar`}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<AppleIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
)
);
})
: null}
{!profileData?.microsoftAccounts && (
<Button
onPress={() => handleMicrosoftSignIn()}
label={"Connect Outlook"}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<OutlookIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
)}
{profileData?.microsoftAccounts
? Object.keys(profileData?.microsoftAccounts)?.map(
(microsoftEmail) => {
const microsoftToken =
profileData?.microsoftAccounts?.[microsoftEmail];
return (
microsoftToken && (
<Button
key={microsoftEmail}
label={`Connected ${microsoftEmail}`}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<OutlookIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
)
);
}
)
: null}
</View>
<View flexG/>
<View width={"100%"}>
<Button
label={hasSomeCalendarsSynced ? "Continue" : "Skip this step"}
onPress={() => setRedirectOverride(false)}
marginT-50
labelStyle={{
fontFamily: "PlusJakartaSans_600SemiBold",
fontSize: 16,
}}
style={{height: 50}}
backgroundColor="#fd1775"
/>
</View>
</View>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
addCalBtn: {
backgroundColor: "#ffffff",
marginBottom: 15,
justifyContent: "flex-start",
paddingLeft: 25,
},
backBtn: {
backgroundColor: "red",
marginLeft: -2,
justifyContent: "flex-start",
},
card: {
backgroundColor: "white",
width: "100%",
padding: 20,
paddingBottom: 30,
marginTop: 20,
borderRadius: 12,
},
noPaddingCard: {
backgroundColor: "white",
width: "100%",
marginTop: 20,
borderRadius: 12,
},
colorBox: {
aspectRatio: 1,
justifyContent: "center",
alignItems: "center",
width: 51,
borderRadius: 12,
},
checkbox: {
borderRadius: 50,
},
addCalLbl: {
fontSize: 16,
fontFamily: "PlusJakartaSan_500Medium",
flexWrap: "wrap",
width: "75%",
textAlign: "left",
lineHeight: 20,
overflow: "visible",
},
subTitle: {
fontFamily: "Manrope_600SemiBold",
fontSize: 18,
},
cardTitle: {
fontFamily: "Manrope_500Medium",
fontSize: 15,
},
});

View File

@ -1,5 +1,5 @@
import Entry from "@/components/pages/main/Entry";
export default function Screen() {
return <Entry />;
return <Entry />;
}

View File

@ -0,0 +1,169 @@
import {SafeAreaView} from "react-native-safe-area-context";
import {Button, Colors, Dialog, LoaderScreen, Text, View} from "react-native-ui-lib";
import React, {useCallback, useState} from "react";
import {useRouter} from "expo-router";
import QRIcon from "@/assets/svgs/QRIcon";
import {Camera, CameraView} from "expo-camera";
import {useLoginWithQrCode} from "@/hooks/firebase/useLoginWithQrCode";
import {useAuthContext} from "@/contexts/AuthContext";
import debounce from "debounce";
export default function Screen() {
const router = useRouter()
const {setRedirectOverride} = useAuthContext()
const [hasPermission, setHasPermission] = useState<boolean | null>(null);
const [showCameraDialog, setShowCameraDialog] = useState<boolean>(false);
const {mutateAsync: signInWithQrCode, isLoading} = useLoginWithQrCode();
const debouncedRouterReplace = useCallback(
debounce(() => {
router.push("/(unauth)/cal_sync");
}, 300),
[]
);
const handleQrCodeScanned = async ({data}: { data: string }) => {
setShowCameraDialog(false);
setRedirectOverride(true);
try {
await signInWithQrCode({userId: data});
debouncedRouterReplace()
} catch (err) {
console.log(err)
}
};
const getCameraPermissions = async (callback: () => void) => {
const {status} = await Camera.requestCameraPermissionsAsync();
setHasPermission(status === "granted");
if (status === "granted") {
callback();
}
};
const handleOpenQrCodeDialog = () => {
getCameraPermissions(() => setShowCameraDialog(true));
}
return (
<SafeAreaView style={{flex: 1}}>
<View style={{flex: 1, padding: 21, paddingBottom: 45, paddingTop: "20%", alignItems: "center"}}>
<View center>
<Text style={{fontSize: 30, fontFamily: 'Manrope_600SemiBold'}}>
Get started with Cally
</Text>
</View>
<View width={"100%"} gap-30>
<View>
<Button
label="Scan QR Code"
marginT-50
labelStyle={{
fontFamily: "PlusJakartaSans_400Regular",
fontSize: 16,
marginLeft: 10
}}
iconSource={() => <QRIcon color={"#07B8C7"}/>}
onPress={handleOpenQrCodeDialog}
style={{height: 50}}
color={Colors.black}
backgroundColor={Colors.white}
/>
{/* GOOGLE LOGIN HERE */}
</View>
<View row center gap-20>
<View flexG style={{backgroundColor: "#E2E2E2", height: 2}}/>
<Text style={{fontSize: 16, fontFamily: 'PlusJakartaSans_300Light', color: "#7A7A7A"}}>
or
</Text>
<View flexG style={{backgroundColor: "#E2E2E2", height: 2}}/>
</View>
<View>
<Button
label="Contine with Email"
labelStyle={{
fontFamily: "PlusJakartaSans_400Regular",
fontSize: 16,
marginLeft: 10
}}
onPress={() => router.push("/(unauth)/sign_up")}
style={{height: 50, borderStyle: "solid", borderColor: "#E2E2E2", borderWidth: 2}}
color={Colors.black}
backgroundColor={"transparent"}
/>
</View>
</View>
<View flexG/>
<View row centerH gap-5>
<Text style={{
fontFamily: "PlusJakartaSans_300Light",
fontSize: 16,
color: "#484848"
}} center>
Already have an account?
</Text>
<Button
label="Log in"
link
onPress={() => router.push("/(unauth)/sign_in")}
labelStyle={[
{
fontFamily: "PlusJakartaSans_500Medium",
fontSize: 16,
color: "#919191",
},
{fontSize: 16, textDecorationLine: "none", color: "#fd1775"},
]}
/>
</View>
</View>
{/* Legacy, move into separate component */}
{/* Camera Dialog */}
<Dialog
visible={showCameraDialog}
onDismiss={() => setShowCameraDialog(false)}
bottom
width="100%"
height="70%"
containerStyle={{padding: 15, backgroundColor: "white"}}
>
<Text center style={{fontSize: 16}} marginB-15>
Scan a QR code presented from your family member of provider.
</Text>
{hasPermission === null ? (
<Text>Requesting camera permissions...</Text>
) : !hasPermission ? (
<Text>No access to camera</Text>
) : (
<CameraView
style={{flex: 1, borderRadius: 15}}
onBarcodeScanned={handleQrCodeScanned}
barcodeScannerSettings={{
barcodeTypes: ["qr"],
}}
/>
)}
<Button
label="Cancel"
onPress={() => setShowCameraDialog(false)}
backgroundColor="#fd1775"
style={{margin: 10, marginBottom: 30}}
/>
</Dialog>
{isLoading && (
<LoaderScreen overlay message={"Signing in..."} backgroundColor={Colors.white} color={Colors.grey40}/>
)}
</SafeAreaView>
)
}

View File

@ -1,10 +1,44 @@
import Entry from "@/components/pages/main/Entry";
import {SafeAreaView} from "react-native-safe-area-context";
import {Button, Image, Text, View} from "react-native-ui-lib";
import React from "react";
import {useRouter} from "expo-router";
export default function Screen() {
const router = useRouter()
return (
<SafeAreaView>
<Entry/>
<SafeAreaView style={{flex: 1}}>
<View style={{flex: 1, padding: 21, paddingBottom: 45, paddingTop: "20%", alignItems: "center"}}>
<View>
<Image source={require("../../assets/images/splash.png")}/>
</View>
<View center gap-13>
<Text style={{fontSize: 40, fontFamily: 'Manrope_600SemiBold', marginLeft: 5}}>
Welcome to Cally
</Text>
<Text center color={"#919191"} style={{fontSize: 20, maxWidth: 250}}>
Lightening Mental Loads,
One Family at a Time
</Text>
</View>
<View flexG/>
<View width={"100%"}>
<Button
label="Continue"
marginT-50
labelStyle={{
fontFamily: "PlusJakartaSans_600SemiBold",
fontSize: 16,
}}
onPress={() => router.push("/(unauth)/get_started")}
style={{height: 50}}
backgroundColor="#fd1775"
/>
</View>
</View>
</SafeAreaView>
)
}
}

View File

@ -0,0 +1,6 @@
import React from "react";
import {ResetPasswordPage} from "@/components/pages/main/ResetPasswordPage";
export default function Screen() {
return <ResetPasswordPage/>
}

6
app/(unauth)/sign_in.tsx Normal file
View File

@ -0,0 +1,6 @@
import SignInPage from "@/components/pages/main/SignInPage";
import React from "react";
export default function Screen() {
return <SignInPage/>
}

8
app/(unauth)/sign_up.tsx Normal file
View File

@ -0,0 +1,8 @@
import React from "react";
import SignUpPage from "@/components/pages/main/SignUpPage";
export default function Screen() {
return (
<SignUpPage/>
)
}