diff --git a/app.json b/app.json
index 6eaee96..4a73aff 100644
--- a/app.json
+++ b/app.json
@@ -62,7 +62,8 @@
"color": "#ffffff",
"defaultChannel": "default"
}
- ]
+ ],
+ "expo-font"
],
"experiments": {
"typedRoutes": true
diff --git a/app/(auth)/_layout.tsx b/app/(auth)/_layout.tsx
index 2edbd97..714d3b4 100644
--- a/app/(auth)/_layout.tsx
+++ b/app/(auth)/_layout.tsx
@@ -43,7 +43,7 @@ export default function TabLayout() {
return (
- Welcome to Cally
+ Welcome to Cally
props.navigation.navigate("settings")}
label={"Manage Settings"}
+ labelStyle={{fontFamily: "Manrope_500Medium"}}
iconSource={() => (
signOut()}
/>
diff --git a/app/_layout.tsx b/app/_layout.tsx
index 1b0128e..b4e3938 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -1,44 +1,207 @@
-import {DefaultTheme, ThemeProvider} from '@react-navigation/native';
-import {useFonts} from 'expo-font';
-import {Stack} from 'expo-router';
-import * as SplashScreen from 'expo-splash-screen';
-import {useEffect} from 'react';
-import 'react-native-reanimated';
-import {AuthContextProvider} from "@/contexts/AuthContext";
-import {QueryClient, QueryClientProvider} from "react-query";
-import {Toast} from "react-native-ui-lib";
+import React, { useEffect } from "react";
+import { DefaultTheme, ThemeProvider } from "@react-navigation/native";
+import {
+ useFonts,
+ Manrope_200ExtraLight,
+ Manrope_300Light,
+ Manrope_400Regular,
+ Manrope_500Medium,
+ Manrope_600SemiBold,
+ Manrope_700Bold,
+ Manrope_800ExtraBold,
+} from "@expo-google-fonts/manrope";
+import { Stack } from "expo-router";
+import * as SplashScreen from "expo-splash-screen";
+import "react-native-reanimated";
+import { AuthContextProvider } from "@/contexts/AuthContext";
+import { QueryClient, QueryClientProvider } from "react-query";
+import {
+ ThemeManager,
+ Typography,
+ Toast,
+ TextProps,
+} from "react-native-ui-lib";
+import functions from "@react-native-firebase/functions";
+import auth from "@react-native-firebase/auth";
+import firestore from "@react-native-firebase/firestore";
SplashScreen.preventAutoHideAsync();
const queryClient = new QueryClient();
+if (__DEV__) {
+ functions().useEmulator('localhost', 5001);
+ firestore().useEmulator("localhost", 5471);
+ auth().useEmulator("http://localhost:9099");
+}
+
+type TextStyleBase =
+ | "text10"
+ | "text20"
+ | "text30"
+ | "text40"
+ | "text50"
+ | "text60"
+ | "text70"
+ | "text80"
+ | "text90"
+ | "text100";
+type TextStyleModifier = "R" | "M" | "BO" | "H" | "BL" | "L";
+type TextStyle = TextStyleBase | `${TextStyleBase}${TextStyleModifier}`;
+
+type TextStyleProps = {
+ [K in TextStyle]?: boolean;
+};
+
+type ExtendedTextProps = TextProps & TextStyleProps;
+
+interface FontStyle {
+ fontFamily: string;
+ fontSize: number;
+}
+
+const getManropeFontStyle = (style: TextStyle): FontStyle => {
+ let fontFamily: string;
+ let fontSize: number;
+
+ if (style.includes("L") || style.includes("BL"))
+ fontFamily = "Manrope_300Light";
+ else if (style.includes("R")) fontFamily = "Manrope_400Regular";
+ else if (style.includes("M")) fontFamily = "Manrope_500Medium";
+ else if (style.includes("BO") || style.includes("H"))
+ fontFamily = "Manrope_700Bold";
+ else {
+ const baseStyle = style.slice(0, 6) as TextStyleBase;
+ switch (baseStyle) {
+ case "text10":
+ case "text20":
+ fontFamily = "Manrope_700Bold";
+ break;
+ case "text30":
+ case "text40":
+ fontFamily = "Manrope_600SemiBold";
+ break;
+ case "text50":
+ fontFamily = "Manrope_400Regular";
+ break;
+ default:
+ fontFamily = "Manrope_300Light";
+ }
+ }
+
+ switch (style.slice(0, 6) as TextStyleBase) {
+ case "text10":
+ fontSize = 64;
+ break;
+ case "text20":
+ fontSize = 50;
+ break;
+ case "text30":
+ fontSize = 36;
+ break;
+ case "text40":
+ fontSize = 28;
+ break;
+ case "text50":
+ fontSize = 24;
+ break;
+ case "text60":
+ fontSize = 20;
+ break;
+ case "text70":
+ fontSize = 16;
+ break;
+ case "text80":
+ fontSize = 14;
+ break;
+ case "text90":
+ fontSize = 12;
+ break;
+ case "text100":
+ fontSize = 10;
+ break;
+ default:
+ fontSize = 16;
+ }
+
+ return { fontFamily, fontSize };
+};
+
export default function RootLayout() {
- const [loaded] = useFonts({
- SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
- });
+ const [loaded] = useFonts({
+ Manrope_200ExtraLight,
+ Manrope_300Light,
+ Manrope_400Regular,
+ Manrope_500Medium,
+ Manrope_600SemiBold,
+ Manrope_700Bold,
+ Manrope_800ExtraBold,
+ });
+
+ useEffect(() => {
+ if (loaded) {
+ SplashScreen.hideAsync();
+
+ const typographies: Partial> = {};
+ (
+ [
+ "text10",
+ "text20",
+ "text30",
+ "text40",
+ "text50",
+ "text60",
+ "text70",
+ "text80",
+ "text90",
+ "text100",
+ ] as const
+ ).forEach((baseStyle) => {
+ typographies[baseStyle] = getManropeFontStyle(baseStyle);
+ (["R", "M", "BO", "H", "BL", "L"] as const).forEach((modifier) => {
+ const style = `${baseStyle}${modifier}` as TextStyle;
+ typographies[style] = getManropeFontStyle(style);
+ });
+ });
- useEffect(() => {
- if (loaded) {
- SplashScreen.hideAsync();
+ Typography.loadTypographies(typographies);
+
+ ThemeManager.setComponentTheme(
+ "Text",
+ (props: ExtendedTextProps, context: unknown) => {
+ const textStyle = (
+ Object.keys(props) as Array
+ ).find((key) => typographies[key as TextStyle]) as
+ | TextStyle
+ | undefined;
+
+ return {
+ style: [
+ Typography.text50,
+ textStyle ? typographies[textStyle] : undefined,
+ ],
+ };
}
- }, [loaded]);
+ );
+ }
+ }, [loaded]);
- if (!loaded) {
- return null;
- }
+ if (!loaded) {
+ return null;
+ }
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/assets/fonts/Manrope-VariableFont_wght.ttf b/assets/fonts/Manrope-VariableFont_wght.ttf
new file mode 100644
index 0000000..f39ca39
Binary files /dev/null and b/assets/fonts/Manrope-VariableFont_wght.ttf differ
diff --git a/assets/images/child-picture.png b/assets/images/child-picture.png
new file mode 100644
index 0000000..5669ec4
Binary files /dev/null and b/assets/images/child-picture.png differ
diff --git a/assets/images/child1-picture.png b/assets/images/child1-picture.png
new file mode 100644
index 0000000..09a5ba1
Binary files /dev/null and b/assets/images/child1-picture.png differ
diff --git a/assets/images/profile-picture.png b/assets/images/profile-picture.png
new file mode 100644
index 0000000..f36ba43
Binary files /dev/null and b/assets/images/profile-picture.png differ
diff --git a/assets/svgs/FireworksOrangeIcon.tsx b/assets/svgs/FireworksOrangeIcon.tsx
new file mode 100644
index 0000000..6600231
--- /dev/null
+++ b/assets/svgs/FireworksOrangeIcon.tsx
@@ -0,0 +1,21 @@
+import * as React from "react"
+import Svg, { G, Path, Defs, ClipPath, SvgProps } from "react-native-svg"
+
+const FireworksOrangeIcon: React.FC = (props) => (
+
+)
+export default FireworksOrangeIcon
diff --git a/assets/svgs/GiftIcon.tsx b/assets/svgs/GiftIcon.tsx
new file mode 100644
index 0000000..ee4be5d
--- /dev/null
+++ b/assets/svgs/GiftIcon.tsx
@@ -0,0 +1,23 @@
+import * as React from "react";
+import Svg, { Path, SvgProps } from "react-native-svg";
+const GiftIcon: React.FC = (props) => (
+
+);
+export default GiftIcon;
diff --git a/components/pages/brain_dump/BrainDumpPage.tsx b/components/pages/brain_dump/BrainDumpPage.tsx
index 111ea6d..071854e 100644
--- a/components/pages/brain_dump/BrainDumpPage.tsx
+++ b/components/pages/brain_dump/BrainDumpPage.tsx
@@ -54,21 +54,20 @@ const BrainDumpPage = () => {
height: 40,
borderRadius: 30,
backgroundColor: "#fd1775",
- alignItems: "center",
- justifyContent: "center",
}}
- centerV
color="white"
enableShadow
- iconSource={() => (
-
- )}
onPress={() => {
setIsAddVisible(true);
}}
- label="New"
- text60R
- />
+ >
+
+
+
+ New
+
+
+
{
padding-15
style={{ borderRadius: 20, elevation: 2 }}
>
-
+
{props.item.title}
- {props.item.description}
+ {props.item.description}
diff --git a/components/pages/brain_dump/DumpList.tsx b/components/pages/brain_dump/DumpList.tsx
index 86453ae..8cd8efb 100644
--- a/components/pages/brain_dump/DumpList.tsx
+++ b/components/pages/brain_dump/DumpList.tsx
@@ -19,7 +19,7 @@ const DumpList = (props: { searchText: string }) => {
);
return (
-
+
item.title}
diff --git a/components/pages/calendar/AddEventDialog.tsx b/components/pages/calendar/AddEventDialog.tsx
index 2731d95..0ef37a6 100644
--- a/components/pages/calendar/AddEventDialog.tsx
+++ b/components/pages/calendar/AddEventDialog.tsx
@@ -20,7 +20,6 @@ import AddChoreDialog from "../todos/AddChoreDialog";
import { ToDosContextProvider } from "@/contexts/ToDosContext";
import UploadImageDialog from "./UploadImageDialog";
-
export const AddEventDialog = () => {
const [show, setShow] = useState(false);
const [showManualInputModal, setShowManualInputModal] = useState(false);
@@ -37,127 +36,137 @@ export const AddEventDialog = () => {
const handleScanImageDialog = () => {
setShow(false);
setTimeout(() => {
- setShowUploadDialog(true);
+ setShowUploadDialog(true);
}, 100);
- }
+ };
return (
-
- <>
-
);
};
diff --git a/components/pages/calendar/CalendarPage.tsx b/components/pages/calendar/CalendarPage.tsx
index 457c969..b928bfa 100644
--- a/components/pages/calendar/CalendarPage.tsx
+++ b/components/pages/calendar/CalendarPage.tsx
@@ -41,6 +41,8 @@ export default function CalendarPage() {
const styles = StyleSheet.create({
segmentslblStyle: {
fontSize: 14,
+ fontFamily: 'Manrope',
+ fontWeight: 'bold'
},
calHeader: {
borderWidth: 0,
@@ -89,7 +91,7 @@ export default function CalendarPage() {
};
return (
-
+
{
text70L
iconSource={() => }
style={styles.finishShopBtn}
+ labelStyle={styles.addBtnLbl}
enableShadow
- onPress={() => {setIsAddingGrocery(true)}}
+ onPress={() => {
+ setIsAddingGrocery(true);
+ }}
/>
@@ -89,4 +92,5 @@ const styles = StyleSheet.create({
flex: 1,
marginHorizontal: 3,
},
+ addBtnLbl: { fontFamily: "Manrope_500Medium", fontSize: 17, marginLeft: 5 },
});
diff --git a/components/pages/grocery/GroceryList.tsx b/components/pages/grocery/GroceryList.tsx
index fe87ee9..1743c4d 100644
--- a/components/pages/grocery/GroceryList.tsx
+++ b/components/pages/grocery/GroceryList.tsx
@@ -1,13 +1,17 @@
-import {FlatList, StyleSheet} from "react-native";
-import React, {useEffect, useState} from "react";
-import {Button, Text, View} from "react-native-ui-lib";
+import { FlatList, StyleSheet } from "react-native";
+import React, { useEffect, useState } from "react";
+import { Button, Text, TouchableOpacity, View } from "react-native-ui-lib";
import GroceryItem from "./GroceryItem";
-import {GroceryCategory, GroceryFrequency, useGroceryContext,} from "@/contexts/GroceryContext";
+import {
+ GroceryCategory,
+ GroceryFrequency,
+ useGroceryContext,
+} from "@/contexts/GroceryContext";
import HeaderTemplate from "@/components/shared/HeaderTemplate";
-import {AntDesign, MaterialIcons} from "@expo/vector-icons";
+import { AntDesign, MaterialIcons } from "@expo/vector-icons";
import EditGroceryItem from "./EditGroceryItem";
-import {ProfileType, useAuthContext} from "@/contexts/AuthContext";
-import {IGrocery} from "@/hooks/firebase/types/groceryData";
+import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
+import { IGrocery } from "@/hooks/firebase/types/groceryData";
const GroceryList = () => {
const {
@@ -81,20 +85,35 @@ const GroceryList = () => {
message={"Welcome to your grocery list"}
isWelcome={false}
>
-
+
-
+
{approvedGroceries?.length} list{" "}
{approvedGroceries?.length === 1 ? (
-
+
item
) : (
-
+
items
)}
@@ -103,19 +122,21 @@ const GroceryList = () => {
-
+
{pendingGroceries?.length} pending
- (
-
- )}
- />
+
+
+
@@ -167,38 +188,42 @@ const GroceryList = () => {
renderItem={({ item }) => (
updateGroceryItem({...changes, id: id})}
+ handleItemApproved={(id, changes) =>
+ updateGroceryItem({ ...changes, id: id })
+ }
/>
)}
keyExtractor={(item) => item.id.toString()}
/>
)
- : pendingVisible && No items pending approval.}
+ : pendingVisible && (
+ No items pending approval.
+ )}
{/* Approved Section */}
{approvedVisible && (
- {
- setApprovedVisible(false);
- }}
- />
+ {
+ setApprovedVisible(false);
+ }}
+ />
)}
{!approvedVisible && (
- {
- setApprovedVisible(true);
- }}
- />
+ {
+ setApprovedVisible(true);
+ }}
+ />
)}
Shopping List
@@ -245,7 +270,9 @@ const GroceryList = () => {
updateGroceryItem({...changes, id: id})}
+ handleItemApproved={(id, changes) =>
+ updateGroceryItem({ ...changes, id: id })
+ }
/>
)
)}
@@ -254,7 +281,9 @@ const GroceryList = () => {
keyExtractor={(category) => category}
/>
)
- : approvedVisible && No approved items.}
+ : approvedVisible && (
+ No approved items.
+ )}
);
};
@@ -263,6 +292,10 @@ const styles = StyleSheet.create({
dropIcon: {
marginHorizontal: 10,
},
+ noItemTxt: {
+ fontFamily: "Manrope_400Regular",
+ fontSize: 14,
+ },
});
export default GroceryList;
diff --git a/components/pages/grocery/GroceryWrapper.tsx b/components/pages/grocery/GroceryWrapper.tsx
index 18174c5..7d82393 100644
--- a/components/pages/grocery/GroceryWrapper.tsx
+++ b/components/pages/grocery/GroceryWrapper.tsx
@@ -19,7 +19,7 @@ const GroceryWrapper = () => {
}, [isAddingGrocery]);
return (
-
+
{
-
{!isAddingGrocery && }
+
);
};
diff --git a/components/pages/todos/ProgressCard.tsx b/components/pages/todos/ProgressCard.tsx
index ed7a16d..c82d1aa 100644
--- a/components/pages/todos/ProgressCard.tsx
+++ b/components/pages/todos/ProgressCard.tsx
@@ -3,6 +3,7 @@ import React from "react";
import { Fontisto } from "@expo/vector-icons";
import { ProgressBar } from "react-native-ui-lib/src/components/progressBar";
import { useToDosContext } from "@/contexts/ToDosContext";
+import FireworksOrangeIcon from "@/assets/svgs/FireworksOrangeIcon";
const ProgressCard = ({children}: {children?: React.ReactNode}) => {
const { maxPoints } = useToDosContext();
@@ -14,8 +15,8 @@ const ProgressCard = ({children}: {children?: React.ReactNode}) => {
style={{ borderRadius: 22 }}
>
-
-
+
+
You have earned XX points this week!{" "}
@@ -30,8 +31,8 @@ const ProgressCard = ({children}: {children?: React.ReactNode}) => {
}}
/>
- 0
- {maxPoints}
+ 0
+ {maxPoints}
{children}
diff --git a/components/pages/todos/ToDoItem.tsx b/components/pages/todos/ToDoItem.tsx
index 948d5dd..b4c5948 100644
--- a/components/pages/todos/ToDoItem.tsx
+++ b/components/pages/todos/ToDoItem.tsx
@@ -13,7 +13,8 @@ import React, { useEffect, useState } from "react";
import { useToDosContext } from "@/contexts/ToDosContext";
import { Ionicons } from "@expo/vector-icons";
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";
const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
const { updateToDo } = useToDosContext();
@@ -33,8 +34,8 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
return (
{
opacity: props.item.done ? 0.3 : 1,
}}
>
-
+
{!editing ? (
{
if (props.isSettings) {
@@ -62,7 +65,7 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
value={props.item.title}
text70R
onChangeText={(text) => {
- updateToDo({id: props.item.id, title: text });
+ updateToDo({ id: props.item.id, title: text });
}}
onSubmitEditing={() => {
setEditing(false);
@@ -74,8 +77,10 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
)}
{
- updateToDo({id: props.item.id, done: !props.item.done });
+ updateToDo({ id: props.item.id, done: !props.item.done });
}}
/>
@@ -90,7 +95,7 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
centerH
/>
-
+
{props.item.points && props.item.points > 0 ? (
{
@@ -99,19 +104,24 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
}
}}
>
-
+
- {props.item.points} points
+
+ {props.item.points} points
+
) : (
)}
-