diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f05e1ba..9889a4f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -25,15 +25,13 @@ stages: lint_job: stage: lint - image: "reactnativecommunity/react-native-android:latest" + image: node rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" when: manual - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH script: - npm install - - npx expo install - - npx expo customize tsconfig.json - npx tsc cache: policy: pull-push @@ -51,9 +49,7 @@ build_job: when: manual script: - echo BUILD_JOB_ID=$CI_JOB_ID >> environment.env - - npm install -g sharp-cli - - npm install expo - - npx expo customize tsconfig.json + - yarn add expo - npx expo prebuild --platform android - cd android && ./gradlew assembleRelease - cd $CI_PROJECT_DIR diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index e561888..971359c 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -24,12 +24,12 @@ Our design philosophy was rooted in simplicity and functionality. We aimed to cr - **Component Development**: Built reusable components for uniformity and efficiency. - **State Management and Hooks**: Implemented custom hooks for state management, ensuring smooth data flow and component reusability. -- [x] **Stage 4: Implementation-Phase 2** +- [ ] **Stage 4: Implementation-Phase 2** - **Refining Components**: Enhancing component functionality and aesthetics. - **Optimization and Debugging**: Identifying and fixing bugs, optimizing code for better performance. - **Expanding Features**: Implementing additional pages and components to enrich the application. -- [x] **Stage 5: Final Implementation-Phase** +- [ ] **Stage 5: Final Implementation-Phase** - **UI Touch-Ups**: Final tweaks to the user interface, ensuring a polished look and feel. - **Finalization**: Wrapping up the project, finalizing drafts, and completing outstanding tasks. diff --git a/README.md b/README.md index 378d956..b5967dd 100644 --- a/README.md +++ b/README.md @@ -25,16 +25,9 @@ A more convenient way to run Finanzfuchs is to download the prebuilt apk which c ## Usage -- **Adding Expenses(/Savings)**: Press the plus button to add expenses. -- **Removing Expenses(/Savings)**: Go to the certain expense and press it. You will then be directed to the edit expense tab, where you can change the expense as you wish. -- **Adding Categories**: Go to the budget tab and press the plus button to add a new category with custom color. -- **Removing Categories**: Go to a certain category by pressing on the budget tab and choosing one. At the top is a big button with a pencil on it, which when you press it takes you to the edit category tab, where you can customize the category or remove it completely with all expenses it contains. -- **Searching for Expenses, Savings and Categories**: At the Home Screen, the Budget tab or in a certain category you can search for certain expenses, categories or savings by writing its name in the Search bar. -- **Home Screen**: Go to the login screen by pressing the profile picture in the top left of the home screen. Furthermore, at the bottom there are the last expenses, which were added. - - **Calendar**: The calendar has little colored dots under certain days indicating, that at that day an expense has been added. By pressing at a day the list of expenses below it will be sorted out and only showing the expenses which were added at that day. - - **List of Expenses**: The list shows the most recently added expenses which can be searched through and filtered by using the calendar. - - **Profile**: By pressing at the profile picture on the home screen you get to the My Profile tab where you can activate the dark mode, reset the database and sign out of the app. -- **Stats**: Here is a Graph showing an Overview of your Budget and the sums of all expenses and savings. +- **Adding Expenses**: Press the plus button to add expenses. +- **Removing Expenses**: Go to the budget tab and press the red button in the middle to reset expenses. +- **Login Screen**: Go to the login screen by pressing the profile picture in the top left of the home screen. ## Team diff --git a/app/(tabs)/(budget)/_layout.tsx b/app/(tabs)/(budget)/_layout.tsx deleted file mode 100644 index c0835eb..0000000 --- a/app/(tabs)/(budget)/_layout.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Stack } from "expo-router"; - -export default function _Layout() { - return ( - - - - - - - ); -} \ No newline at end of file diff --git a/app/(tabs)/(budget)/addCategory.tsx b/app/(tabs)/(budget)/addCategory.tsx deleted file mode 100644 index 695a708..0000000 --- a/app/(tabs)/(budget)/addCategory.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { router, useLocalSearchParams } from "expo-router"; -import { useState } from "react"; -import { StyleSheet, Text, TextInput, View } from "react-native"; -import { SafeAreaView } from 'react-native-safe-area-context'; -import { AutoDecimalInput, CustomColorPicker, NavigationButton, TypeSelectorSwitch } from "../../../components"; -import { addCategory } from "../../../services/database"; -import { useTheme } from "../../contexts/ThemeContext"; -import { CategoryType } from "../../../types/dbItems"; - -export default function Page() { - const {colors} = useTheme(); - - const parameters = useLocalSearchParams(); - - const [categoryName, setCategoryName] = useState(""); - const [categoryColor, setCategoryColor] = useState('#' + Math.floor(Math.random()*16777215).toString(16)); - - const [selectedType, setSelectedType] = useState(CategoryType.EXPENSE); - - const [amount, setAmount] = useState(0); - - return ( - - Add Category - - - - { - setCategoryName(newName); - }}/> - - - - { - setAmount(!Number.isNaN(Number.parseFloat(value)) ? Number.parseFloat(value) : 0); - }}/> - - - { - setSelectedType(type); - }} - /> - - - { - setCategoryColor(color); - }}/> - - - - { - router.back(); - }}/> - { - addCategory(categoryName, categoryColor, selectedType, amount).then(() => router.back()); - }}/> - - - - ); -} - -const styles = StyleSheet.create({ - containerStyle: { - flex: 1, - margin: 10, - borderRadius: 10, - }, - safeAreaViewStyle: { - flex: 1, - flexDirection: "column" - }, - headingTextStyle: { - fontSize: 40, - fontWeight: "bold", - alignSelf: "center", - marginVertical: 10, - }, - navigationButtonViewStyle: { - flexDirection: "row", - justifyContent: "center", - marginBottom: 10, - }, - textInputViewStyle: { - borderRadius: 10, - paddingVertical: 10, - margin: 10, - }, - textInputStyle: { - paddingHorizontal: 10, - fontSize: 25, - }, - budgetInput: { - marginBottom: 10, - marginHorizontal: 10, - } -}); \ No newline at end of file diff --git a/app/(tabs)/(budget)/category.tsx b/app/(tabs)/(budget)/category.tsx deleted file mode 100644 index 93d0374..0000000 --- a/app/(tabs)/(budget)/category.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { FontAwesome } from "@expo/vector-icons"; -import { useRouter, useLocalSearchParams } from "expo-router"; -import { FlatList, StyleSheet, Text, TouchableOpacity, View } from "react-native"; -import { ExpenseItem, LoadingSymbol, TextInputBar, EmptyListCompenent, Plus } from "../../../components"; -import useFetch from "../../../hooks/useFetch"; -import { useTheme } from "../../contexts/ThemeContext"; -import { SafeAreaView } from "react-native-safe-area-context"; -import { useNavigation } from "expo-router/src/useNavigation"; -import { useEffect } from "react"; - -export default function Page() { - const router = useRouter(); - const navigation = useNavigation(); - const {colors} = useTheme(); - const {category_guid} = useLocalSearchParams(); - - const {category_amount, category_color, category_name, category_type} = fetchCategoryInformation(category_guid.toString()); - - const {data, isLoading, reFetch} = useFetch({sql: "SELECT e.guid AS expense_guid, e.name AS expense_name, c.name AS category_name, e.datetime AS expense_datetime, e.amount AS expense_amount, c.color AS category_color FROM expense e JOIN category c ON e.category_guid = c.guid WHERE c.guid = ? ORDER BY expense_datetime desc;", args: [category_guid]}); - - const handleEditCategory = () => { - router.push({pathname: "/editCategory", params: {category_guid: category_guid, category_color: category_color, category_amount: category_amount, category_name: category_name, category_type: category_type}}); - } - - const handleBackButton = () => { - router.back(); - } - - useEffect(() => { - console.log("useEffect called") - const unsubscribe = navigation.addListener("focus", () => { - reFetch(); - }) - return unsubscribe; - }, [navigation]) - - return ( - - router.push(`/expense/new?category=${category_guid}`)}/> - - - Back - - - - {category_name} - - - - - - {isLoading ? () : ( - router.push(`/expense/${item.expense_guid}`)} - />} - keyExtractor={item => item.expense_guid} - ItemSeparatorComponent={() => { - return (); - }} - ListEmptyComponent={EmptyListCompenent} - /> - )} - - ); -} - -const fetchCategoryInformation = (guid: string) => { - - const {data} = useFetch({sql: "SELECT * FROM category WHERE guid = ?", args: [guid]}); - - let category_name = ""; - let category_color = ""; - let category_amount = 0; - let category_type = ""; - - if (data && data[0]) { - if ("name" in data[0]) category_name = data[0].name as string; - if ("color" in data[0]) category_color = data[0].color as string; - if ("allocated_amount" in data[0]) category_amount = data[0].allocated_amount as number; - if ("type" in data[0]) category_type = data[0].type as string; - } - - return {category_name, category_color, category_amount, category_type}; -} - -const styles = StyleSheet.create({ - safeAreaView: { - flex: 1, - }, - itemSeperator: { - margin: 5, - }, - categoryEditTouchableOpacity: { - borderRadius: 10, - flexDirection: "row", - justifyContent: "space-around", - margin: 10, - }, - editButtonText: { - fontSize: 30, - padding: 10, - fontWeight: "bold", - }, - iconEdit: { - paddingVertical: 10, - paddingRight: 10, - }, - searchBar: { - marginHorizontal: 10, - marginBottom:20, - }, - iconBack: { - paddingLeft: 10, - paddingRight: 5, - }, - backText: { - fontSize: 20, - padding: 5, - }, - backContainer: { - flexDirection: "row", - justifyContent: "flex-start", - } -}); diff --git a/app/(tabs)/(budget)/editCategory.tsx b/app/(tabs)/(budget)/editCategory.tsx deleted file mode 100644 index 19dc3e0..0000000 --- a/app/(tabs)/(budget)/editCategory.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { router, useLocalSearchParams } from "expo-router"; -import { useState } from "react"; -import { StyleSheet, Text, TextInput, View } from "react-native"; -import { AutoDecimalInput, CustomColorPicker, NavigationButton, TypeSelectorSwitch, Plus } from "../../../components"; -import useFetch from "../../../hooks/useFetch"; -import { deleteCategory, deleteExpense, updateCategory } from "../../../services/database"; -import { useTheme } from "../../contexts/ThemeContext"; -import { SafeAreaView } from 'react-native-safe-area-context'; -import { CategoryType } from "../../../types/dbItems"; - -const addCategory = () => { - const {colors} = useTheme(); - const {category_guid, category_amount, category_color, category_name, category_type} = useLocalSearchParams(); - - const [categoryName, setCategoryName] = useState(category_name.toString()); - const [categoryColor, setCategoryColor] = useState(category_color.toString()); - const [selectedType, setSelectedType] = useState(category_type === "expense" ? CategoryType.EXPENSE : CategoryType.SAVING); - const [amount, setAmount] = useState(Number.parseFloat(category_amount.toString())); - - const {data} = useFetch({sql: "SELECT * FROM expense WHERE category_guid = ?", args: [category_guid.toString()]}); - - return ( - - Edit Category - - - { - setCategoryName(newName); - }}/> - - - - { - setAmount(!Number.isNaN(Number.parseFloat(value)) ? Number.parseFloat(value) : 0); - }}/> - - - { - setSelectedType(type); - }} - /> - - - { - setCategoryColor(color); - }}/> - - - - { - for (let i = 0; i < data.length;) { - deleteExpense(data[i].guid).then(() => { - i++ - }); - } - deleteCategory(category_guid.toString()).then(() => { - router.push("/(tabs)/(budget)"); - }); - }}/> - - - - { - router.back(); - }}/> - { - updateCategory(category_guid.toString(), categoryName, categoryColor, selectedType, amount).then(() => { - router.back(); - }); - }}/> - - - - ); -} - -export default addCategory; - -const styles = StyleSheet.create({ - deleteButtonView: { - - }, - containerStyle: { - flex: 1, - margin: 10, - borderRadius: 10, - }, - safeAreaViewStyle: { - flex: 1, - flexDirection: "column" - }, - headingTextStyle: { - fontSize: 40, - fontWeight: "bold", - alignSelf: "center", - marginVertical: 10, - }, - navigationButtonViewStyle: { - flexDirection: "row", - justifyContent: "center", - marginBottom: 10, - }, - textInputViewStyle: { - borderRadius: 10, - paddingVertical: 10, - margin: 10, - }, - textInputStyle: { - paddingHorizontal: 10, - fontSize: 25, - }, - budgetInput: { - marginBottom: 10, - marginHorizontal: 10, - } -}); \ No newline at end of file diff --git a/app/(tabs)/(budget)/index.tsx b/app/(tabs)/(budget)/index.tsx deleted file mode 100644 index fce6f05..0000000 --- a/app/(tabs)/(budget)/index.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import AsyncStorage from '@react-native-async-storage/async-storage'; -import { router, useNavigation } from 'expo-router'; -import React, { useEffect, useMemo, useState } from 'react'; -import { StyleSheet, View } from 'react-native'; -import { FlatList } from 'react-native-gesture-handler'; -import { SafeAreaView } from 'react-native-safe-area-context'; -import { BudgetHeader, CategoryItem, EmptyListCompenent, LoadingSymbol, Plus, TextInputBar } from '../../../components'; -import useFetch from '../../../hooks/useFetch'; -import { useTheme } from '../../contexts/ThemeContext'; -import { useFocusEffect } from 'expo-router/src/useFocusEffect'; - -export default function Page() { - const {colors} = useTheme() - const containerColor = colors.containerColor; - const navigation = useNavigation(); - const [selectedPage, setSelectedPage] = useState<"expense"|"saving">("expense"); - const [searchString, setSearchString] = useState(""); - - - - // useEffect(() => { - // console.log("initial effect called") - // AsyncStorage.getItem("currentBudgetPage").then((page) => { - // if(page === "expenses" || page === "savings") { - // setSelectedPage(page); - // } - // }).catch((error) => { - // console.log("Error fetching previous page from Async Storage:", error); - // }) - // }, []); - - const {data, isLoading, reFetch} = useFetch({sql: "SELECT c.guid AS category_guid, c.name AS category_name, c.color AS category_color, c.type AS category_type, SUM(e.amount) as total_expenses, c.allocated_amount as allocated_amount FROM category c LEFT JOIN expense e ON e.category_guid = c.guid GROUP BY c.guid", args: []}); - - useEffect(() => { - reFetch() - }, [selectedPage]); - - - useEffect(() => { - const unsubscribe = navigation.addListener("focus", () => { - - reFetch(); - }) - - const t = () => { - console.log("unsubscribed") - unsubscribe(); - } - return t; - }, [navigation]) - - - const handlePageSelection = (page: "expense" | "saving") => { - setSelectedPage(page); - }; - - const handleCategoryPress = (item: {[column: string]: any;}) => { - router.push({pathname: "/category", params: {category_guid: item.category_guid, category_name: item.category_name}}) - } - - const filteredData = useMemo(() => { - return data.filter((item) => { - if(item.category_type !== selectedPage) { - return false - } - return item.category_name.toLowerCase().includes(searchString.toLowerCase()); - }) - }, [data, searchString, selectedPage]); - - return ( - - - - - - { - router.push({pathname: '/addCategory'}); - }}/> - - {isLoading ? () : ( - { - handleCategoryPress(item); - }}/>} - keyExtractor={item => item.category_guid} - ItemSeparatorComponent={() => { - return (); - }} - ListEmptyComponent={EmptyListCompenent} - /> - )} - - - ); -} - -const styles = StyleSheet.create({ - safeAreaViewStyle: { - flex: 1, - }, - itemSeperatorStyle: { - marginVertical: 5, - }, -}); \ No newline at end of file diff --git a/app/(tabs)/(home)/index.tsx b/app/(tabs)/(home)/index.tsx deleted file mode 100644 index f76b36a..0000000 --- a/app/(tabs)/(home)/index.tsx +++ /dev/null @@ -1,218 +0,0 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { NativeScrollEvent, NativeSyntheticEvent, StyleSheet, View } from 'react-native'; -import { Calendar } from 'react-native-calendars'; -import { FlatList, RefreshControl } from 'react-native-gesture-handler'; -import { SafeAreaView } from 'react-native-safe-area-context'; -import { EmptyListCompenent, ExpenseItem, LoadingSymbol, Plus, TextInputBar, Welcome } from '../../../components'; -import useFetch from '../../../hooks/useFetch'; - -import { useRouter } from "expo-router"; -import { addExpense } from "../../../services/database"; -import { SimpleDate } from '../../../util/SimpleDate'; -import { useTheme } from '../../contexts/ThemeContext'; -import { useNavigation } from 'expo-router'; -import { Category, Expense } from '../../../types/dbItems'; - - -interface MarkingProps { - dots?:{color:string, selectedColor?:string, key?:string}[]; - selected?: boolean; - selectedColor?: string; -} - -type MarkedDates = { - [key: string]: MarkingProps; -} - -interface ExpenseEntry extends Expense { - category_name?: string; - color?: string; -} - -type Filters = { - search?: string; - month?: string; - day?: string; -} - -const constructMarkedDates = (data : {[column: string]: any}) => { - let markedDates: MarkedDates = {}; - data.forEach((value: any) => { - const dateKey: string = String(value["expense_datetime"]).split(" ")[0] - - if(markedDates[dateKey] === undefined){ - markedDates[dateKey] = {dots: []} - } - markedDates[dateKey].dots?.push({color: value["category_color"]}) - }) - return markedDates; -} - -export default function Page() { - const { colors, theme } = useTheme() - - const navigation = useNavigation(); - const router = useRouter(); - const [plusShow, setPlusShow] = useState(true); - const prevOffset = useRef(0); - - const [filter, setFilter] = useState({}) - - const profile = require("../../../assets/images/profile.jpg") - - const handleScroll = (event: NativeSyntheticEvent)=>{ - const currentOffset = event.nativeEvent.contentOffset.y >= 0 ? event.nativeEvent.contentOffset.y : 0 - const isScrollingUp : boolean = currentOffset <= prevOffset.current; - const isTop : boolean = currentOffset === 0 - prevOffset.current = currentOffset - setPlusShow(isScrollingUp || isTop) - } - - const {data, isLoading, reFetch} = useFetch({sql: "SELECT e.guid AS expense_guid, c.guid AS category_guid, e.name AS expense_name, c.name AS category_name, e.datetime AS expense_datetime, e.amount AS expense_amount, c.color AS category_color, c.type AS category_type FROM expense e JOIN category c ON e.category_guid = c.guid ORDER BY expense_datetime desc;", args: []}); - - const expenses = useMemo( - () => { - console.log("expenses updated") - return data.map((elem) => { - return { - guid: elem["expense_guid"], - name: elem["expense_name"], - amount: elem["expense_amount"], - dateTime: elem["expense_datetime"], - category_name: elem["category_name"], - color: elem["category_color"]} - }) - }, [data]) - - const filteredExpenses = useMemo( - () => { - console.log("filter called") - return expenses.filter((elem) => { - if(filter.month && filter.month.substring(5, 7) !== elem.dateTime?.substring(5, 7)){ - return false; - } - if(filter.day && filter.day.substring(8, 10) !== elem.dateTime?.substring(8, 10)){ - return false; - } - if(filter.search && !elem.name?.toLowerCase().includes(filter.search.toLowerCase())){ - return false; - } - return true; - }) - }, [expenses, filter] - ) - - const expenseDates = useMemo( - () => { - let markedDates = constructMarkedDates(data) - if(filter.day) { - const dateKey: string = String(filter.day).split(" ")[0] - if(markedDates[dateKey] === undefined){ - markedDates[dateKey] = {} - } - markedDates[dateKey].selected = true; - markedDates[dateKey].selectedColor = colors.accentColor; - } - return markedDates; - } - , [data, filter.day]) - - useEffect(() => { - const unsubscribe = navigation.addListener('focus', () => { - console.log("focus event triggered") - reFetch(); - }); - return unsubscribe; - }, [navigation]); - - const hanldeDaySelect = (date: string | undefined) => { - if(filter.day === date) - setFilter({...filter, day: undefined}); - else - setFilter({...filter, day: date}); - } - const handleMonthSelect = (date: string | undefined) => { - setFilter({...filter, month: date, day: undefined}); - } - const handleSearch = (text: string) => { - setFilter({...filter, search: text}); - } - - console.log("rendered") - return ( - - {plusShow && { - router.push("/expense/new"); - - // executeQuery({sql: "SELECT guid FROM category", args: []}).then((result) => { - // if("rows" in result[0]) { - // newExpense("Test Title", result[0]["rows"][0]["guid"], "69.69.1234", 100).then(() => { - // reFetch(); - // }); - // } - // }) - }}/>} - - {/* {isLoading && } */} - - - {router.push("/userSettings")}}/> - { - hanldeDaySelect(date.dateString) - }} - onMonthChange={(date) => { - handleMonthSelect(date.dateString) - }} - /> - - handleSearch(text)} style={{marginBottom: 20}}> - - } - renderItem = {({item}) => - {router.push(`/expense/${guid}`)}} - />} - keyExtractor={item => item.guid!} - ItemSeparatorComponent={() => { - return (); - }} - refreshControl={ - - } - onScroll={handleScroll} - scrollEventThrottle={20} - ListEmptyComponent={EmptyListCompenent} - /> - - ); -} - -const styles = StyleSheet.create({ - safeAreaViewStyle: { - flex: 1, - paddingHorizontal: 10 - }, - itemSeperatorStyle: { - marginVertical: 5, - } -}); \ No newline at end of file diff --git a/app/(tabs)/(stats)/index.tsx b/app/(tabs)/(stats)/index.tsx deleted file mode 100644 index 5113d08..0000000 --- a/app/(tabs)/(stats)/index.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react'; - -import { Graph } from '../../../components'; -import BudgetOverview from '../../../components/stats/BudgetOverview'; -import BudgetRemaining from '../../../components/stats/SavingsOverview'; -import SavingsOverview from '../../../components/stats/SavingsOverview'; -import Widget from '../../../components/stats/Widget'; -import FinancialAdvice from '../../../components/stats/FinancialAdvice'; -import BudgetTotal from '../../../components/stats/BudgetTotal'; -import { ScrollView } from 'react-native-gesture-handler'; -import { SafeAreaView } from 'react-native-safe-area-context'; -import DebugMenu from '../../../services/DebugMenu'; - -export default function Page() { - - return ( - - - {/* */} - - - - - - - - - - - - {/* - - */} - - - - - ); -} diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 62d5907..4eb7245 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -3,9 +3,9 @@ import { StyleSheet } from "react-native"; import { FontAwesome } from "@expo/vector-icons"; import { Redirect } from "expo-router"; -import React from "react"; -import { useAuth } from "../contexts/AuthContext"; +import React, { useEffect } from "react"; import { useTheme } from "../contexts/ThemeContext"; +import { useAuth } from "../contexts/AuthContext"; export default function Layout() { const {authState} = useAuth() @@ -25,7 +25,6 @@ export default function Layout() { tabBarInactiveTintColor: colors.tabIconDefault, headerShown: false, tabBarStyle: styles.tabBar, - tabBarHideOnKeyboard: true } if(!authState?.authenticated){ @@ -34,27 +33,31 @@ export default function Layout() { } return ( - - + ( ), + unmountOnBlur: true, + href: "(tabs)/budget" } }/> - ( ), + unmountOnBlur: true, + href: "(tabs)/home/" } }/> - ( ), + unmountOnBlur: true, } }/> diff --git a/app/(tabs)/budget/_layout.tsx b/app/(tabs)/budget/_layout.tsx new file mode 100644 index 0000000..5c62492 --- /dev/null +++ b/app/(tabs)/budget/_layout.tsx @@ -0,0 +1,16 @@ +import { Stack } from "expo-router"; +import { useTheme } from "../../contexts/ThemeContext"; + +export default function _Layout() { + const { colors } = useTheme(); + return ( + + + + + ); +} \ No newline at end of file diff --git a/app/(tabs)/budget/addCategory.tsx b/app/(tabs)/budget/addCategory.tsx new file mode 100644 index 0000000..e8edbbc --- /dev/null +++ b/app/(tabs)/budget/addCategory.tsx @@ -0,0 +1,8 @@ + +const addCategory = () => { + return ( + <> + ); +} + +export default addCategory; \ No newline at end of file diff --git a/app/(tabs)/budget/index.tsx b/app/(tabs)/budget/index.tsx new file mode 100644 index 0000000..4ca010e --- /dev/null +++ b/app/(tabs)/budget/index.tsx @@ -0,0 +1,70 @@ +import AsyncStorage from '@react-native-async-storage/async-storage'; +import { router } from 'expo-router'; +import { useEffect, useState } from 'react'; +import { StyleSheet, View } from 'react-native'; +import { FlatList } from 'react-native-gesture-handler'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { BudgetHeader, LoadingSymbol, Plus } from '../../../components'; +import CategoryItem from '../../../components/budget/categoryItem'; +import useFetch from '../../../hooks/useFetch'; +import { useTheme } from '../../contexts/ThemeContext'; + +export default function Page() { + const {colors} = useTheme() + const containerColor = colors.containerColor; + + const [selectedPage, setSelectedPage] = useState("noPageLoaded"); + + useEffect(() => { + AsyncStorage.getItem("currentBudgetPage").then((page) => { + if(page === "expenses" || page === "savings") { + setSelectedPage(page); + } + }).catch((error) => { + console.log("Error fetching previous page from Async Storage:", error); + }) + }, []); + + const {data, isLoading, reFetch} = useFetch({sql: "SELECT c.guid AS category_guid, c.name AS category_name, c.color AS category_color, c.type AS category_type, SUM(e.amount) as total_expenses, c.allocated_amount as allocated_amount FROM expense e RIGHT JOIN category c ON e.category_guid = c.guid WHERE c.type = ? GROUP BY c.guid", args: selectedPage === "expenses" ? ["expense"] : selectedPage === "savings" ? ["saving"] : []}); + + useEffect(() => { + reFetch(); + }, [selectedPage]); + + const handlePageSelection = (page: string) => { + if(page !== selectedPage) { + setSelectedPage(page); + AsyncStorage.setItem("currentBudgetPage", page); + } + }; + + return ( + + + + { + router.push("/(tabs)/budget/addCategory") + }}/> + + {isLoading ? () : ( + } + keyExtractor={item => item.category_guid} + ItemSeparatorComponent={() => { + return (); + }} + /> + )} + + ); +} + +const styles = StyleSheet.create({ + safeAreaViewStyle: { + flex: 1, + }, + itemSeperatorStyle: { + marginVertical: 5, + }, +}); \ No newline at end of file diff --git a/app/(tabs)/(home)/_layout.tsx b/app/(tabs)/home/_layout.tsx similarity index 84% rename from app/(tabs)/(home)/_layout.tsx rename to app/(tabs)/home/_layout.tsx index 8e16222..f6c2a2b 100644 --- a/app/(tabs)/(home)/_layout.tsx +++ b/app/(tabs)/home/_layout.tsx @@ -12,10 +12,10 @@ export default function _Layout() { initialRouteName="index" screenOptions={{ contentStyle: { - backgroundColor:colors.containerColor, + backgroundColor:colors.backgroundColor, }, headerStyle: { - backgroundColor: colors.containerColor + backgroundColor: colors.backgroundColor }, headerTintColor: colors.primaryText @@ -24,6 +24,7 @@ export default function _Layout() { title: "test", headerShown: false, }}/> + + addItem + + ) +} \ No newline at end of file diff --git a/app/(tabs)/home/index.tsx b/app/(tabs)/home/index.tsx new file mode 100644 index 0000000..eaa0b22 --- /dev/null +++ b/app/(tabs)/home/index.tsx @@ -0,0 +1,131 @@ +import React, { useRef, useState, useMemo } from 'react'; +import { NativeScrollEvent, NativeSyntheticEvent, StyleSheet, View } from 'react-native'; +import { Calendar } from 'react-native-calendars'; +import { FlatList } from 'react-native-gesture-handler'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { ExpenseItem, LoadingSymbol, Plus, SearchBar, Welcome } from '../../../components'; +import useFetch from '../../../hooks/useFetch'; + +import { addExpense, executeQuery } from "../../../services/database"; +import { useAuth } from '../../contexts/AuthContext'; +import { useRouter } from "expo-router"; +import { SimpleDate } from '../../../util/SimpleDate'; +import { useTheme } from '../../contexts/ThemeContext'; + + +interface MarkingProps { + dots?:{color:string, selectedColor?:string, key?:string}[]; +} + +type MarkedDates = { + [key: string]: MarkingProps; +} + +const constructMarkedDates = (data : {[column: string]: any}) => { + console.log("entered") + let markedDates: MarkedDates = {}; + data.forEach((value: any) => { + const dateKey: string = String(value["expense_datetime"]).split(" ")[0] + + if(markedDates[dateKey] === undefined){ + markedDates[dateKey] = {dots: []} + } + markedDates[dateKey].dots?.push({color: value["category_color"]}) + }) + return markedDates; +} + +export default function Page() { + const { colors, theme } = useTheme() + + + + const router = useRouter(); + const [plusShow, setPlusShow] = useState(true); + const prevOffset = useRef(0); + + + const profile = require("../../../assets/images/profile.jpg") + + const handleScroll = (event: NativeSyntheticEvent)=>{ + const currentOffset = event.nativeEvent.contentOffset.y >= 0 ? event.nativeEvent.contentOffset.y : 0 + const isScrollingUp : boolean = currentOffset <= prevOffset.current; + const isTop : boolean = currentOffset === 0 + prevOffset.current = currentOffset + setPlusShow(isScrollingUp || isTop) + } + + const newExpense = async (title: string, category_guid: string, date: string, amount: number) => { + try { + await addExpense(title, category_guid, date, amount); + } catch (error: any) { + console.error("Adding new expense has failed: ", error); + } + } + + const {data, isLoading, reFetch} = useFetch({sql: "SELECT e.guid AS expense_guid, c.guid AS category_guid, e.name AS expense_name, c.name AS category_name, e.datetime AS expense_datetime, e.amount AS expense_amount, c.color AS category_color, c.type AS category_type FROM expense e JOIN category c ON e.category_guid = c.guid;", args: []}); + + const expenseDates = useMemo(()=> + constructMarkedDates(data) + , [data]) + + + + return ( + + {plusShow && { + // router.push("/(tabs)/home/addItem"); + + executeQuery({sql: "SELECT guid FROM category", args: []}).then((result) => { + if("rows" in result[0]) { + newExpense("Test Title", result[0]["rows"][0]["guid"], "69.69.1234", 100).then(() => { + reFetch(); + }); + } + }) + }}/>} + + {isLoading && } + + + {router.push("/home/userSettings")}}/> + + + + + + } + renderItem = {({item}) => } + keyExtractor={item => item.expense_guid} + ItemSeparatorComponent={() => { + return (); + }} + onScroll={handleScroll} + scrollEventThrottle={20} + /> + + ); +} + +const styles = StyleSheet.create({ + safeAreaViewStyle: { + flex: 1, + }, + itemSeperatorStyle: { + marginVertical: 5, + } +}); \ No newline at end of file diff --git a/app/(tabs)/(home)/userSettings.tsx b/app/(tabs)/home/userSettings.tsx similarity index 86% rename from app/(tabs)/(home)/userSettings.tsx rename to app/(tabs)/home/userSettings.tsx index fb163ae..c865110 100644 --- a/app/(tabs)/(home)/userSettings.tsx +++ b/app/(tabs)/home/userSettings.tsx @@ -4,7 +4,7 @@ import { SIZES } from '../../../constants/theme' import { SafeAreaView } from 'react-native-safe-area-context' import { ButtonSetting, ToggleSetting } from '../../../components' import { useTheme } from '../../contexts/ThemeContext' -import { deleteCategories, deleteExpenses, DEV_populateDatabase } from '../../../services/database' +import { deleteExpenses, DEV_populateDatabase } from '../../../services/database' import { useAuth } from '../../contexts/AuthContext' import { TouchableOpacity } from 'react-native-gesture-handler' @@ -50,14 +50,17 @@ export default function userSettings() { - { - const deleteAll = async () => { - await deleteExpenses(); - await deleteCategories(); - } - deleteAll(); - }} + { + deleteExpenses().then(() => { + console.log("Expenses Deleted!"); + })}} /> + { + const del = async () => { + await DEV_populateDatabase() + } + del() + }}/> diff --git a/app/(tabs)/stats/index.tsx b/app/(tabs)/stats/index.tsx new file mode 100644 index 0000000..9dd775a --- /dev/null +++ b/app/(tabs)/stats/index.tsx @@ -0,0 +1,61 @@ +import { Query } from 'expo-sqlite'; +import { StyleSheet, Text, View } from 'react-native'; +import { addCategory, deleteDatabase, deleteExpenses, executeQuery, initDatabase } from '../../../services/database'; + +export default function Page() { + const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'space-evenly', + alignItems: 'center', + }, + text: { + fontSize: 40, + color: "yellow", + } + }); + + return ( + + { + deleteExpenses().then(() => { + console.log("Expenses Deleted!"); + }) + }}>Reset Expenses + + { + deleteDatabase(); + console.log("Database Deleted!"); + }}>Reset Database + + { + initDatabase().then(() => { + console.log("Database Initialized!"); + }); + }}>Init Database + + { + addCategory("Category", "green", "expense", 500).then(() => { + const getCategoryQuery: Query = {sql: "SELECT guid FROM category", args: []}; + executeQuery(getCategoryQuery).then((result) => { + if("rows" in result[0]) { + console.log(result[0]["rows"]); + } + }) + console.log("Category added with success!"); + }) + }}>Add new Category Expense + + { + addCategory("Category", "yellow", "saving", 420).then(() => { + const getCategoryQuery: Query = {sql: "SELECT guid FROM category", args: []}; + executeQuery(getCategoryQuery).then((result) => { + if("rows" in result[0]) { + console.log(result[0]["rows"]); + } + }) + console.log("Category added with success!"); + }) + }}>Add new Category Savings + ); +} diff --git a/app/_layout.tsx b/app/_layout.tsx index e99a541..f34a4ea 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -1,37 +1,20 @@ -import { SplashScreen, Stack } from 'expo-router'; +import { Slot } from 'expo-router'; import React, { useEffect } from 'react'; import { addCategory, initDatabase } from '../services/database'; import { AuthProvider } from './contexts/AuthContext'; import { ThemeProvider } from './contexts/ThemeContext'; -import { useTheme } from './contexts/ThemeContext'; - export default function _layout() { - const {colors} = useTheme(); + useEffect(() => { initDatabase(); - }, []); - console.log(colors.backgroundColor) return ( - - - - - - - - + + + + + ) } \ No newline at end of file diff --git a/app/expense/[expense].tsx b/app/expense/[expense].tsx deleted file mode 100644 index 1eb15ff..0000000 --- a/app/expense/[expense].tsx +++ /dev/null @@ -1,137 +0,0 @@ -import { View, Text, Alert, StyleSheet } from 'react-native' -import React, { useEffect, useState } from 'react' -import { router, useLocalSearchParams, useRouter } from 'expo-router' -import useFetch from '../../hooks/useFetch'; -import { Category, Expense } from '../../types/dbItems'; -import { CategorySelectorModal, AutoDecimalInput, CategorySelector, TextInputBar, DateSelectorButton, RoundedButton } from '../../components'; -import colors from '../../constants/colors'; -import { addExpense, deleteExpense, executeQuery, updateExpense } from '../../services/database'; -import { SimpleDate } from '../../util/SimpleDate'; -import DateTimePicker from '@react-native-community/datetimepicker'; -import { SIZES } from '../../constants/theme'; -import { useTheme } from '../contexts/ThemeContext'; - -export default function Page() { - const router = useRouter(); - const {colors} = useTheme(); - const {expense} = useLocalSearchParams(); - const {data, isEmptyResult} = useFetch({sql: "SELECT e.guid as e_guid, e.name as e_name, e.datetime as e_datetime, e.amount as e_amount, c.guid as c_guid, c.name as c_name, c.color as c_color FROM expense e INNER JOIN category c on e.category_guid = c.guid WHERE e.guid = ?", args: [expense]}); - const [selectedExpense, setSelectedExpense] = useState(); - const [selectedCategory, setSelectedCategory] = useState(); - const [formatedValue, setFormatedValue] = useState(""); - const [initialValue, setInitialValue] = useState(); - const [selectorModalVisible, setSelecorModalVisible] = useState(false); - const [expenseName, setExpenseName] = useState(""); - const [datePickerShown, setDatePickerShown] = useState(false); - const [selectedDate, setSelectedDate] = useState(new Date()); - - useEffect(()=>{ - const entry = data[0]; - console.log(entry) - if(entry){ - console.log(entry) - const extractedExpense: Expense = {name: entry["e_name"], amount: entry["e_amount"], dateTime: entry["e_datetime"], guid: entry["e_guid"]} - const extractedCategory: Category = {name: entry["c_name"], color: entry["c_color"], guid: entry["c_guid"]} - - console.log(extractedCategory.color) - - setSelectedExpense(extractedExpense); - setSelectedCategory(extractedCategory); - setInitialValue(extractedExpense.amount) - setExpenseName(extractedExpense.name ?? "") - setSelectedDate(extractedExpense.dateTime? new Date(extractedExpense.dateTime) : new Date()); - } - - - }, [data]) - - const handleValueChange = (formatedValue: string) => { - setFormatedValue(formatedValue); - } - - const handleCategorySelect = (category : Category) => { - setSelecorModalVisible(false); - setSelectedCategory(category); - } - - const validateInput = ():boolean => { - if(formatedValue == "" || expenseName == "" || selectedCategory === undefined || selectedDate === null){ - return false; - } - return true; - } - - const submit = () => { - console.log(selectedExpense?.guid) - const insert = async () => { - await updateExpense(selectedExpense!.guid!, expenseName, selectedCategory!.guid!, new SimpleDate(selectedDate).format("YYYY-MM-DD"), Number(formatedValue)) - } - if(validateInput()){ - insert().then( () => router.back()) - }else { - Alert.alert("Invalid input", "One of the Props is not properly defined") - } - - } - - const handleDelete = () => { - const del = async () => { - await deleteExpense(selectedExpense!.guid!) - router.back(); - } - del(); - } - - return ( - - {setSelecorModalVisible(false)}} onCategoryTap={handleCategorySelect}> - - {setSelecorModalVisible(true)}} selectedCategory={selectedCategory}/> - setExpenseName(text)} value={expenseName}/> - {setDatePickerShown(true)}}/> - {datePickerShown && - { - setDatePickerShown(false); - if(date){ - setSelectedDate(date); - } - }} - />} - - Delete Expense - - - Save - - - ) -} - -const styles = StyleSheet.create({ - notFound: { - alignItems: "center", - justifyContent: "center" - }, - - notFoundMessageContainer: { - backgroundColor: "#e37b7b", - padding: 50, - }, - save: { - padding: 10, - }, - container: { - margin: SIZES.normal, - display: "flex", - gap: 10 - }, - - submitText: { - fontSize: SIZES.large - } - -}) \ No newline at end of file diff --git a/app/expense/_layout.tsx b/app/expense/_layout.tsx deleted file mode 100644 index f867c8a..0000000 --- a/app/expense/_layout.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { StyleSheet, Text, View } from 'react-native' -import { Stack } from 'expo-router' -import React from 'react' -import { useTheme } from '../contexts/ThemeContext' - -const _layout = () => { - const {colors} = useTheme(); - return ( - - - String(Date.now())} - /> - - ) -} - -export default _layout - -const styles = StyleSheet.create({}) \ No newline at end of file diff --git a/app/expense/new.tsx b/app/expense/new.tsx deleted file mode 100644 index bfbd7bd..0000000 --- a/app/expense/new.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { View, Text, StyleSheet, Alert } from 'react-native' -import React, { useEffect, useRef, useState } from 'react' -import { SIZES } from '../../constants/theme' -import { useTheme } from '../contexts/ThemeContext' -import { AutoDecimalInput, CategorySelector, CategorySelectorModal, DateSelectorButton, RoundedButton, TextInputBar } from '../../components' -import { Category } from '../../types/dbItems' -import DateTimePicker from '@react-native-community/datetimepicker'; -import { addExpense, executeQuery } from '../../services/database' -import { SimpleDate } from '../../util/SimpleDate' -import { useLocalSearchParams, useRouter } from 'expo-router' - -export default function AddItem() { - const {colors} = useTheme(); - const router = useRouter(); - - const searchParams = useLocalSearchParams() - - const [formatedValue, setFormatedValue] = useState(""); - const [selectorModalVisible, setSelecorModalVisible] = useState(false); - const [selectedCategory, setSelectedCategory] = useState() - const [expenseName, setExpenseName] = useState(""); - const [datePickerShown, setDatePickerShown] = useState(false); - const [selectedDate, setSelectedDate] = useState(new Date()) - - const handleValueChange = (formatedValue: string) => { - setFormatedValue(formatedValue); - } - - const handleCategorySelect = (category : Category) => { - setSelecorModalVisible(false); - setSelectedCategory(category); - } - - const validateInput = ():boolean => { - if(formatedValue == "" || expenseName == "" || selectedCategory === undefined || selectedDate === null){ - return false; - } - return true; - } - - const submit = () => { - const insert = async () => { - await addExpense(expenseName, selectedCategory?.guid!, new SimpleDate(selectedDate).format("YYYY-MM-DD"), Number(formatedValue)) - } - if(validateInput()){ - insert().then(() => { - router.back(); - }) - }else { - Alert.alert("Invalid input", "One of the Props is not properly defined") - } - - } - - useEffect(()=>{ - if(searchParams.category !== undefined){ - executeQuery({sql: "SELECT * FROM category WHERE guid = ?", args: [searchParams.category]}).then((result) =>{ - if("rows" in result[0]){ - const category = result[0]["rows"][0]; - setSelectedCategory({name: category["name"], color: category["color"], guid: category["guid"]}) - } - //setSelectedCategory({name: category["name"], color: category["color"], guid: category["guid"]}) - }) - } - }, []) - - return ( - - {setSelecorModalVisible(false)}} onCategoryTap={handleCategorySelect}> - - {setSelecorModalVisible(true)}} selectedCategory={selectedCategory}/> - setExpenseName(text)}/> - {setDatePickerShown(true)}}/> - {datePickerShown && - { - setDatePickerShown(false); - if(date){ - setSelectedDate(date); - } - }} - />} - - Save - - - ) -} - -const styles = StyleSheet.create({ - save: { - marginTop: 40, - padding: 10, - }, - container: { - margin: SIZES.normal, - display: "flex", - gap: 10 - }, - - submitText: { - fontSize: SIZES.large - } - -}) \ No newline at end of file diff --git a/app/index.tsx b/app/index.tsx index 6b489fe..265d68b 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -7,7 +7,7 @@ export default function index() { const {authState} = useAuth() return ( - + ) } \ No newline at end of file diff --git a/assets/images/8b14el.jpg b/assets/images/8b14el.jpg deleted file mode 100644 index 3e1e0e6..0000000 Binary files a/assets/images/8b14el.jpg and /dev/null differ diff --git a/babel.config.js b/babel.config.js index f76b519..79900d3 100644 --- a/babel.config.js +++ b/babel.config.js @@ -4,7 +4,6 @@ module.exports = function (api) { presets: ['babel-preset-expo'], plugins: [ 'expo-router/babel', - 'react-native-reanimated/plugin', ], }; }; diff --git a/components/budget/budgetHeader.tsx b/components/budget/budgetHeader.tsx index 5e65614..eed9624 100644 --- a/components/budget/budgetHeader.tsx +++ b/components/budget/budgetHeader.tsx @@ -1,10 +1,10 @@ import { StyleSheet, Text, TouchableHighlight, View } from "react-native"; +import SearchBar from "../common/SearchBar"; import { useTheme } from "../../app/contexts/ThemeContext"; -import TextInputBar from "../common/TextInputBar"; type BudgetHeaderProperties = { selectedPage: string, - handlePageSelection: (page: "expense" | "saving") => void, + handlePageSelection: (page: string) => void, } type PageSelectorButtonProperties = { @@ -21,19 +21,20 @@ const BudgetHeader = (properties: BudgetHeaderProperties) => { { - properties.handlePageSelection("expense") + properties.handlePageSelection("expenses") }} /> { - properties.handlePageSelection("saving"); + properties.handlePageSelection("savings"); }} /> + ); } @@ -76,11 +77,8 @@ const styles = StyleSheet.create({ containerStyle: { flexDirection: "row", justifyContent: "space-evenly", + marginHorizontal: 20, marginBottom: 20, - marginHorizontal: 10, marginTop: 10, }, - searchBarStyle: { - marginBottom: 20, - } }); \ No newline at end of file diff --git a/components/budget/categoryItem.tsx b/components/budget/categoryItem.tsx index d64a29b..e651caf 100644 --- a/components/budget/categoryItem.tsx +++ b/components/budget/categoryItem.tsx @@ -1,5 +1,4 @@ import { ColorValue, StyleSheet, Text, View } from "react-native"; -import { TouchableOpacity } from "react-native-gesture-handler"; import { useTheme } from "../../app/contexts/ThemeContext"; import CustomCard from "../common/CustomCard"; @@ -9,56 +8,49 @@ export type CategoryItemProps = { allocated_amount: number, total_expenses: number, category_guid: string, - onPress?: () => void, } const CategoryItem = (properties: CategoryItemProps) => { const { colors } = useTheme(); - const subText = `${properties.total_expenses.toFixed(2)} / ${properties.allocated_amount} €`; + const subText = `${properties.total_expenses} / ${properties.allocated_amount} €`; return ( - - - - - - {properties.category} - - - {subText} - - - - + + + + + {properties.category} + + + {subText} + + + ); }; export default CategoryItem; const styles = StyleSheet.create({ - customCardStyle: { - flexDirection: "row", - justifyContent: "space-between", - }, colorTipStyle: { - width: 25, - borderTopLeftRadius: 10, - borderBottomLeftRadius: 10, + width: 25, + borderTopLeftRadius: 10, + borderBottomLeftRadius: 10, }, textViewStyle: { - flex: 2, - flexDirection: "column", - paddingVertical: 5, - paddingHorizontal: 10, - alignSelf: "stretch", + flex: 2, + flexDirection: "column", + paddingVertical: 5, + paddingHorizontal: 10, + alignSelf: "stretch", }, categoryNameStyle: { - fontSize: 30, - fontWeight: "bold", + fontSize: 30, + fontWeight: "bold", }, subTextStyle: { - fontSize: 17.5, + fontSize: 17.5, } -}); + }) diff --git a/components/budget/customColorPicker.tsx b/components/budget/customColorPicker.tsx deleted file mode 100644 index f601f12..0000000 --- a/components/budget/customColorPicker.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { StyleSheet } from "react-native"; -import ColorPicker, { BrightnessSlider, HueSlider, Preview, SaturationSlider, } from "reanimated-color-picker"; - -export type CustomColorPickerProperties = { - color: string, - handleColorChange: (color: string) => void | undefined, -} - -const CustomColorPicker = (properties: CustomColorPickerProperties) => { - return ( - { - properties.handleColorChange(color["hex"]) - }} - style={styles.colorPickerStyle} - sliderThickness={30} - thumbSize={40} - thumbShape= "circle"> - - - - - - - ); -} - -export default CustomColorPicker; - -const styles = StyleSheet.create({ - colorPickerStyle: { - justifyContent: 'center', - }, - sliderStyle: { - margin: 10, - }, - previewStyle: { - margin: 10, - height: 50, - borderRadius: 10, - } - }); \ No newline at end of file diff --git a/components/budget/typeSelectorSwitch.tsx b/components/budget/typeSelectorSwitch.tsx deleted file mode 100644 index f3e8f25..0000000 --- a/components/budget/typeSelectorSwitch.tsx +++ /dev/null @@ -1,54 +0,0 @@ - -import { StyleSheet, Text, TouchableOpacity, View } from "react-native"; -import { useTheme } from "../../app/contexts/ThemeContext"; -import { CategoryType } from "../../types/dbItems"; - -export type TypeSelectorSwitchProperties = { - handleButtonPress: (type: CategoryType) => void, - currentSelected: CategoryType, -} - -const TypeSelectorSwitch = (properties: TypeSelectorSwitchProperties) => { - const {colors} = useTheme(); - - return ( - - { - properties.handleButtonPress(CategoryType.EXPENSE); - }} - style={[styles.touchableOpacityStyle, properties.currentSelected == CategoryType.EXPENSE ? {backgroundColor: colors.accentColor} : {backgroundColor: colors.elementDefaultColor}] - }> - Expenses - - { - properties.handleButtonPress(CategoryType.SAVING); - }} - style={[styles.touchableOpacityStyle, properties.currentSelected == CategoryType.SAVING ? {backgroundColor: colors.accentColor} : {backgroundColor: colors.elementDefaultColor}] - }> - Savings - - - ); -} - -export default TypeSelectorSwitch; - -const styles = StyleSheet.create({ - containerStyle: { - flexDirection: "row", - justifyContent: "center", - }, - touchableOpacityStyle: { - flex: 1, - marginHorizontal: 10, - borderRadius: 10, - }, - textStyle: { - paddingHorizontal: 10, - fontSize: 25, - textAlign: "center", - paddingVertical: 5, - } -}); \ No newline at end of file diff --git a/components/common/AutoDecimalInput.tsx b/components/common/AutoDecimalInput.tsx deleted file mode 100644 index 260b1ba..0000000 --- a/components/common/AutoDecimalInput.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { View, Text, TouchableOpacity, TextInput, StyleSheet, NativeSyntheticEvent, TextInputKeyPressEventData } from 'react-native' -import React, {LegacyRef, MutableRefObject, useEffect, useRef, useState} from 'react' -import { SIZES } from '../../constants/theme'; -import { useTheme } from '../../app/contexts/ThemeContext'; - -const formatDecimal = (value: string)=>{ - switch(value.length){ - case 0: - return ""; - case 1: - return "0.0"+value - case 2: - return "0."+value - default: - return value.substring(0, value.length - 2) + "." + value.substring(value.length - 2, value.length) - } -} - -interface AutoDecimalInputProps{ - onValueChange?: (formattedValue: string) => void | undefined - label: string, - initialValue? : number -} - -const AutoDecimalInput: React.FC = ({onValueChange, label, initialValue}) => { - const { colors } = useTheme(); - const inputRef = useRef(null); - const [pressedNumbers, setPressedNumbers] = useState(""); - - const init = () => { - if(initialValue){ - const pressedNumber = initialValue.toFixed(2).replace(".", "") - update(pressedNumber); - } - } - - const update = (newValues : string) => { - if(onValueChange){ - onValueChange(formatDecimal(newValues)) - } - setPressedNumbers(newValues); - } - - useEffect(() => { - init() - }, [initialValue]) - - const handleInput = (e: NativeSyntheticEvent)=>{ - const pressedKey:string = e.nativeEvent.key - if(Number.isInteger(Number.parseInt(pressedKey))){ - if(pressedNumbers.length === 0 && pressedKey === "0"){ - return - } - update(pressedNumbers + pressedKey) - }else if(pressedKey === "Backspace"){ - update(pressedNumbers.substring(0, pressedNumbers.length - 1)) - } - } - return ( - { - if(inputRef.current) - inputRef.current.focus() - }}> - {label} - - - EUR - - - ) -} - -const styles = StyleSheet.create({ - inputContainer: { - minHeight: 50, - borderRadius: 20, - flexDirection: "row", - justifyContent: 'space-between', - alignItems: "center" - }, - text:{ - fontSize: SIZES.large, - marginHorizontal: 15, - }, - currency: { - fontSize: SIZES.normal, - color: "#007acc", - marginRight: 15, - }, - currencyWrapper: { - flexDirection:"row", - justifyContent: 'flex-end', - alignItems: "center" - } -}) - -export default AutoDecimalInput; \ No newline at end of file diff --git a/components/common/CategoryListItem.tsx b/components/common/CategoryListItem.tsx deleted file mode 100644 index 3d432a6..0000000 --- a/components/common/CategoryListItem.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { StyleSheet, Text, View, Pressable } from 'react-native' -import React from 'react' -import { Category } from '../../types/dbItems' -import CustomCard from './CustomCard'; -import { SIZES } from '../../constants/theme'; -import { useTheme } from '../../app/contexts/ThemeContext'; - -interface CategoryListItemProps{ - category: Category; - onPress?: (category: Category) =>void | undefined -} - - - -const CategoryListItem: React.FC = (props: CategoryListItemProps) => { - const {category, onPress} = props; - const {colors} = useTheme(); - - const handlePress = ()=>{ - if(onPress){ - onPress(category); - } - } - - return ( - - - - - {category.name ?? "#noData#"} - - - - - ) -} - -export default CategoryListItem - -const styles = StyleSheet.create({ - tile: { - height: 60, - flexDirection: "row", - alignItems: "center", - justifyContent: "space-between", - borderRadius: 20 - }, - colorTip:{ - height: "100%", - width: 30, - borderTopLeftRadius:20, - borderBottomLeftRadius: 20 - }, - textWrapper: { - - }, - tileTail:{ - height: "100%", - width: 30, - borderTopRightRadius:20, - borderBottomRightRadius: 20 - }, - text: { - fontSize: SIZES.large, - } -}) \ No newline at end of file diff --git a/components/common/CustomCard.tsx b/components/common/CustomCard.tsx index 87aae81..5358d51 100644 --- a/components/common/CustomCard.tsx +++ b/components/common/CustomCard.tsx @@ -39,7 +39,11 @@ export default function CustomCard(props : ViewProps) { const styles = StyleSheet.create({ container:{ - borderRadius: 20, + flexDirection: "row", + alignItems: "stretch", + alignContent: "space-between", + borderRadius: 10, + marginHorizontal: 10, }, boxShadow: {}, }) \ No newline at end of file diff --git a/components/common/EmptyListCompenent.tsx b/components/common/EmptyListCompenent.tsx deleted file mode 100644 index c0a1746..0000000 --- a/components/common/EmptyListCompenent.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { View, Text, StyleSheet } from 'react-native' -import React from 'react' -import { useTheme } from '../../app/contexts/ThemeContext' - -const EmptyListCompenent:React.FC = () => { - const {colors} = useTheme(); - return ( - - No matching Data - - ) -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: "center", - alignItems: "center", - height: 70, - borderRadius: 20, - } -}) - -export default EmptyListCompenent \ No newline at end of file diff --git a/components/common/RoundedButton.tsx b/components/common/RoundedButton.tsx deleted file mode 100644 index 1852212..0000000 --- a/components/common/RoundedButton.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { StyleSheet, Text, View, ViewProps, TouchableOpacity } from 'react-native' -import React from 'react' -import { SIZES } from '../../constants/theme'; - -interface RoundedButtonProps extends ViewProps{ - onPress?: ()=> void | undefined; - color: string; -} - -const RoundedButton: React.FC = (props: RoundedButtonProps) => { - const {onPress, color, style, ...restProps} = props; - return ( - - - {restProps.children} - - - ) -} - -export default RoundedButton - -const styles = StyleSheet.create({ - btn:{ - justifyContent: 'center', - alignItems: 'center', - borderRadius: 80 - }, - text: { - fontSize: SIZES.normal - } -}) \ No newline at end of file diff --git a/components/common/TextInputBar.tsx b/components/common/SearchBar.tsx similarity index 60% rename from components/common/TextInputBar.tsx rename to components/common/SearchBar.tsx index bfeaac8..372d052 100644 --- a/components/common/TextInputBar.tsx +++ b/components/common/SearchBar.tsx @@ -1,19 +1,16 @@ import { AntDesign } from '@expo/vector-icons'; -import React, { useState } from 'react'; +import React from 'react'; import { StyleSheet, TextInput, TouchableOpacity, View, ViewProps } from 'react-native'; import { SIZES } from '../../constants/theme'; import { useTheme } from '../../app/contexts/ThemeContext'; -interface SearchBarProps extends ViewProps { - placeholder? : string; - onChangeText? : (text: string) => void | undefined - value?: string -} +type SearchBarProps = {placeholder: string} & ViewProps -export default function TextInputBar(props: SearchBarProps) { +export default function SearchBar(props: SearchBarProps) { const [isActive, setIsactive] = React.useState(false); const { colors } = useTheme(); + const textColor = colors const backgroundColor = colors.elementDefaultColor; const handleChange = (text:string) : void => { @@ -26,10 +23,6 @@ export default function TextInputBar(props: SearchBarProps) { setIsactive(false) } } - if(props.onChangeText){ - props.onChangeText(text) - } - } // cant apply the background color otherwise @@ -41,14 +34,12 @@ export default function TextInputBar(props: SearchBarProps) { //TODO: Handle textCancel // changed styles.container to containerStyle return ( - - (setIsactive(true))} onEndEditing={()=>setIsactive(false)}/> + + {isActive && - { - console.log("cancel") - handleChange("")}}> - + + } @@ -57,6 +48,8 @@ export default function TextInputBar(props: SearchBarProps) { const styles = StyleSheet.create({ container: { + marginHorizontal: 10, + marginBottom: 20, flexDirection: 'row', justifyContent: "center", alignItems: "center", diff --git a/components/common/button.tsx b/components/common/button.tsx deleted file mode 100644 index a846cfd..0000000 --- a/components/common/button.tsx +++ /dev/null @@ -1,39 +0,0 @@ - -import { StyleSheet, Text, TouchableHighlight } from "react-native"; -import { useTheme } from "../../app/contexts/ThemeContext"; - -export type NavigationButtonProperties = { - onPress?: () => void | undefined, - text: string, -} - -const NavigationButton = (properties: NavigationButtonProperties) => { - - const {colors} = useTheme(); - - return ( - - - {properties.text} - - ); -} - -export default NavigationButton; - -const styles = StyleSheet.create({ - touchableHighlightStyle: { - borderRadius: 10, - marginVertical: 10, - marginHorizontal: 15, - paddingHorizontal: 20, - paddingVertical: 5, - }, - buttonTextStyle: { - textAlign: "center", - fontSize: 30, - } -}); diff --git a/components/common/loadingSymbol.tsx b/components/common/loadingSymbol.tsx index 757749c..17fb29a 100644 --- a/components/common/loadingSymbol.tsx +++ b/components/common/loadingSymbol.tsx @@ -1,43 +1,23 @@ -import React, { useEffect, useRef } from "react"; -import { ActivityIndicator, Animated, Easing, StyleSheet, View } from "react-native"; -import { useTheme } from "../../app/contexts/ThemeContext"; +import { StyleSheet, View } from "react-native"; const LoadingSymbol = () => { - const {colors} = useTheme(); - const spinValue = useRef(new Animated.Value(0)).current; + const color = ["blue", "red", "purple", "green", "yellow", "orange"]; + const random = Math.floor(Math.random() * color.length); - useEffect(() => { - Animated.loop( - Animated.timing(spinValue, { - toValue: 1, - duration: 2000, - easing: Easing.linear, - useNativeDriver: true, - }) - ).start(); - }, [spinValue]); + const styles = StyleSheet.create({ + container: { + backgroundColor: color[random], + width: "100%", + height: "100%", + position: "absolute", + } + }); - const styles = StyleSheet.create({ - container: { - width: "100%", - height: "100%", - position: "absolute", - justifyContent: "center", - alignItems: "center", - }, - loader: { - width: 100, - height: 100, - zIndex: 999, - }, - }); - - return ( - - - + return ( + ); -}; +} -export default LoadingSymbol; + +export default LoadingSymbol; \ No newline at end of file diff --git a/components/expense/CategorySelector.tsx b/components/expense/CategorySelector.tsx deleted file mode 100644 index 59e5edf..0000000 --- a/components/expense/CategorySelector.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { StyleSheet, Text, View, TouchableOpacity } from 'react-native' -import React, { useState } from 'react' -import { useTheme } from '../../app/contexts/ThemeContext' -import { SIZES } from '../../constants/theme'; -import { Category } from '../../types/dbItems'; -import CategorySelectorModal from './CategorySelectorModal'; - -interface CategorySelectorProps { - onPress? : () => void | undefined; - selectedCategory? : Category; -} - -const CategorySelector: React.FC = (props : CategorySelectorProps) => { - const {colors} = useTheme(); - - - return ( - <> - - - - - - {props.selectedCategory?.name ?? "Tap to select Categroy"} - - - - - ) -} - -export default CategorySelector - -const styles = StyleSheet.create({ - tile: { - height: 60, - flexDirection: "row", - alignItems: "center", - justifyContent: "space-between", - borderRadius: 20 - }, - colorTip:{ - height: "100%", - width: 30, - borderTopLeftRadius:20, - borderBottomLeftRadius: 20 - }, - textWrapper: { - - }, - tileTail:{ - height: "100%", - width: 30, - borderTopRightRadius:20, - borderBottomRightRadius: 20 - }, - text: { - fontSize: SIZES.large, - } -}) \ No newline at end of file diff --git a/components/expense/CategorySelectorModal.tsx b/components/expense/CategorySelectorModal.tsx deleted file mode 100644 index ef09fd1..0000000 --- a/components/expense/CategorySelectorModal.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { Modal, NativeSyntheticEvent, StyleSheet, Text, View, FlatList } from 'react-native' -import React, { useEffect, useMemo, useState } from 'react' -import { Category } from '../../types/dbItems'; -import { useTheme } from '../../app/contexts/ThemeContext'; -import CategoryListItem from '../common/CategoryListItem'; -import { SIZES } from '../../constants/theme'; -import useFetch from '../../hooks/useFetch'; -import TextInputBar from '../common/TextInputBar'; -import EmptyListCompenent from '../common/EmptyListCompenent'; - - -interface CategorySelectorModalProps{ - visible: boolean; - onCategoryTap?: (category : Category) => void | undefined; - selectMulitple?: boolean; - onRequestClose?: ((event: NativeSyntheticEvent) => void) | undefined; -} - -//TODO: select Multiple - -const CategorySelectorModal: React.FC = (props : CategorySelectorModalProps) => { - const {visible, onCategoryTap, selectMulitple} = props; - const {data, reFetch} = useFetch({sql: "SELECT * FROM category;", args:[]}); - const {colors} = useTheme(); - const [searchtext, setSearchtext] = useState(""); - - const handleSearchText = (text : string) => { - setSearchtext(text); - } - - const categories = useMemo(()=>{ - return data.map((elem) => { - return {name: elem["name"], color: elem["color"], guid: elem["guid"]} - }) - }, [data]) - - const filteredCategories = categories.filter((category) => category.name?.toLowerCase().includes(searchtext.toLowerCase())) - - useEffect(()=>{ - if(visible){ - //reFetch(); Uncomment if newly added categories do not appear - handleSearchText(""); - } - }, [visible]) - - return ( - - - - - {selectMulitple ? "Categories" : "Category"} - - - item.guid!} - renderItem={({item})=> } - ItemSeparatorComponent={() => } - ListFooterComponent={() => } - keyboardShouldPersistTaps="always" - ListEmptyComponent={EmptyListCompenent} - > - - - - - - ) -} - -export default CategorySelectorModal - -const styles = StyleSheet.create({ - main: { - backgroundColor: 'rgba(0, 0, 0, 0.5)', - height: "100%", - width: "100%", - alignItems: "center", - }, - modal: { - height: "70%", - width: "90%", - top: "10%", - borderRadius: 30, - paddingVertical: 20, - paddingHorizontal: 20 - }, - heading: { - fontSize: SIZES.xlarge, - fontWeight: "bold" - }, - itemSeperatorStyle: { - paddingBottom: 10 - } -}) \ No newline at end of file diff --git a/components/expense/DateSelectorButton.tsx b/components/expense/DateSelectorButton.tsx deleted file mode 100644 index ec6916d..0000000 --- a/components/expense/DateSelectorButton.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { View, Text, StyleSheet, TouchableOpacity, TouchableOpacityProps } from 'react-native' -import React, { useState } from 'react' -import { useTheme } from '../../app/contexts/ThemeContext'; -import { SIZES } from '../../constants/theme'; -import { SimpleDate } from '../../util/SimpleDate'; -import { ViewProps } from 'react-native/Libraries/Components/View/ViewPropTypes'; - -interface DateSelectorProps extends ViewProps { - onPress?: ()=>void | undefined; - selectedDate: Date -} - -const DateSelectorButton:React.FC = (props: DateSelectorProps) => { - const {onPress, selectedDate, ...restProps} = props; - const {colors} = useTheme(); - - return ( - - Date: - {new SimpleDate(selectedDate).format("DD.MM.YYYY")} - - ) -} -const styles = StyleSheet.create({ - inputContainer: { - minHeight: 50, - borderRadius: 20, - flexDirection: "row", - justifyContent: 'space-between', - alignItems: "center" - }, - text:{ - fontSize: SIZES.large, - marginHorizontal: 15, - }, -}) - -export default DateSelectorButton \ No newline at end of file diff --git a/components/home/expenseItem.tsx b/components/home/expenseItem.tsx index fd00c7f..d541d48 100644 --- a/components/home/expenseItem.tsx +++ b/components/home/expenseItem.tsx @@ -1,56 +1,36 @@ import React from 'react'; import { ColorValue, StyleSheet, Text, View } from 'react-native'; -import { TouchableOpacity } from 'react-native-gesture-handler'; -import { useTheme } from '../../app/contexts/ThemeContext'; import { SIZES } from '../../constants/theme'; import CustomCard from "../common/CustomCard"; +import { useTheme } from '../../app/contexts/ThemeContext'; -//export type ExpenseItemProps = {color: ColorValue, category: string, title: string, date: string, value : string} -interface ExpenseItemProps { - color: ColorValue; - category: string; - title: string; - date: string; - value : string; - guid? : string; - onPress? : (guid?: string) => void -} - +export type ExpenseItemProps = {color: ColorValue, category: string, title: string, date: string, value : string} export default function ExpenseItem(itemProps : ExpenseItemProps) { const { colors } = useTheme(); - const handlePress = ()=>{ - if(itemProps.onPress){ - itemProps.onPress(itemProps.guid); - } - } return ( - - - - - {itemProps.category} - {itemProps.title} - {itemProps.date} - - - {itemProps.value + " €"} - - - + + + {itemProps.category} + {itemProps.title} + {itemProps.date} + + + {itemProps.value} + + ) @@ -62,12 +42,6 @@ const styles = StyleSheet.create({ borderTopLeftRadius: 20, borderBottomLeftRadius: 20, }, - - tile: { - flexDirection: "row", - alignItems: "stretch", - alignContent: "space-between", - }, textSection: { flexDirection: "column", diff --git a/components/index.tsx b/components/index.tsx index 0c51fed..4d74a43 100644 --- a/components/index.tsx +++ b/components/index.tsx @@ -3,54 +3,20 @@ import { ButtonSetting, ToggleSetting } from "./home/Setting" import Welcome from "./home/Welcome" import ExpenseItem from "./home/expenseItem" -//home/addItem -import CategorySelector from "./expense/CategorySelector" -import CategorySelectorModal from "./expense/CategorySelectorModal" -import DateSelectorButton from "./expense/DateSelectorButton" - //common -import AutoDecimalInput from "./common/AutoDecimalInput" -import CustomCard from "./common/CustomCard" -import RoundedButton from "./common/RoundedButton" -import TextInputBar from "./common/TextInputBar" -import NavigationButton from "./common/button" import LoadingSymbol from "./common/loadingSymbol" import Plus from "./common/plus" -import EmptyListCompenent from "./common/EmptyListCompenent" +import SearchBar from "./common/SearchBar" +import CustomCard from "./common/CustomCard" + //login import BudgetHeader from "./budget/budgetHeader" -import CategoryItem from "./budget/categoryItem" -import CustomColorPicker from "./budget/customColorPicker" -import TypeSelectorSwitch from "./budget/typeSelectorSwitch" - -//login import Input from "./login/input" -//stats -import Graph from "./stats/Graph" - export { - AutoDecimalInput, - BudgetHeader, - ButtonSetting, - CategoryItem, - CategorySelector, - CategorySelectorModal, - CustomCard, - CustomColorPicker, - DateSelectorButton, - EmptyListCompenent, - ExpenseItem, - Graph, - Input, - LoadingSymbol, - NavigationButton, - Plus, - RoundedButton, - TextInputBar, - ToggleSetting, - TypeSelectorSwitch, - Welcome + BudgetHeader, ButtonSetting, CustomCard, ExpenseItem, Input, + LoadingSymbol, Plus, + SearchBar, ToggleSetting, Welcome } diff --git a/components/stats/BudgetOverview.tsx b/components/stats/BudgetOverview.tsx deleted file mode 100644 index 4148e6a..0000000 --- a/components/stats/BudgetOverview.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { Text, StyleSheet } from 'react-native'; -import { useTheme } from '../../app/contexts/ThemeContext'; -import useFetch from '../../hooks/useFetch'; -import { CategoryType } from '../../types/dbItems'; -import {useCategoryData} from '../../hooks/useCategoryData'; - -const styles = StyleSheet.create({ - container: { - margin: 10, - borderRadius: 5, - alignItems: 'center', - justifyContent: 'center' - }, - text: { - fontSize: 26, - color: `black` - }, - boldText: { - fontWeight: 'bold' - }, - negativeText: { - color: 'red', - }, - positiveText: { - color: 'green', - }, -}); - -interface BudgetTotalProps { - goodColor?: string; - badColor?: string; -} - -const BudgetTotal: React.FC = ({ goodColor = 'green', badColor = 'red' }) => { - const { colors } = useTheme(); - const { data, isLoading } = useCategoryData(CategoryType.EXPENSE); - - const { total, expenseTotal } = data; - - const remaining = total - expenseTotal; - - if (isLoading) { - return Loading...; - } - - return ( - - <> - You have spent {expenseTotal.toFixed(2)}€ out of your Budget of {total.toFixed(2)}€ - - - ); -}; - -export default BudgetTotal; \ No newline at end of file diff --git a/components/stats/BudgetTotal.tsx b/components/stats/BudgetTotal.tsx deleted file mode 100644 index f4b0aa8..0000000 --- a/components/stats/BudgetTotal.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { Text, StyleSheet } from 'react-native'; -import { useTheme } from '../../app/contexts/ThemeContext'; -import useFetch from '../../hooks/useFetch'; -import { CategoryType } from '../../types/dbItems'; -import {useCategoryData} from '../../hooks/useCategoryData'; - -const styles = StyleSheet.create({ - container: { - margin: 10, - borderRadius: 5, - alignItems: 'center', - justifyContent: 'center' - }, - text: { - fontSize: 26, - color: `black` - }, - boldText: { - fontWeight: 'bold' - }, - negativeText: { - color: 'red', - }, - positiveText: { - color: 'green', - }, -}); - -interface BudgetTotalProps { - goodColor?: string; - badColor?: string; -} - -const BudgetTotal: React.FC = ({ goodColor = 'green', badColor = 'red' }) => { - const { colors } = useTheme(); - const { data, isLoading } = useCategoryData(CategoryType.EXPENSE); - - const { total, expenseTotal } = data; - - const remaining = total - expenseTotal; - - if (isLoading) { - return Loading...; - } - - return ( - - {remaining >= 0 ? ( - <> - Your remaining overall Budget is {remaining.toFixed(2)}€ - - ) : ( - <> - Your Budget is overspent by -{Math.abs(remaining).toFixed(2)}€ - - )} - - ); -}; - -export default BudgetTotal; \ No newline at end of file diff --git a/components/stats/CategoryProgressBar.tsx b/components/stats/CategoryProgressBar.tsx deleted file mode 100644 index 4e49975..0000000 --- a/components/stats/CategoryProgressBar.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import React from 'react'; -import { View, Text, StyleSheet } from 'react-native'; -import { useTheme } from '../../app/contexts/ThemeContext'; - -interface CategoryProgressBarProps { - categoryName: string; - color?: string; - maxValue: number; - currentValue: number; -} - -const CategoryProgressBar: React.FC = ({ - categoryName, - color, - maxValue, - currentValue, -}) => { - const { colors } = useTheme(); - - const progress = (currentValue / maxValue) * 100; - const progressText = `${currentValue}€ / ${maxValue}€`; - - const dynamicStyles = StyleSheet.create({ - progressBarFill: { - height: '100%', - width: `${progress}%`, - backgroundColor: color || colors.accentColor, - alignItems: 'center', - justifyContent: 'center', - }, - progressText: { - color: colors.primaryText, - fontSize: 20, - fontWeight: 'bold', - }, - }); - - const styles = StyleSheet.create({ - container: { - padding: 10, - }, - progressBarContainer: { - flexDirection: 'row', - height: 50, - backgroundColor: colors.elementSelectedColor, - borderRadius: 15, - overflow: 'hidden', - marginTop: 4, - }, - categoryName: { - color: colors.primaryText, - fontSize: 20, - fontWeight: 'bold', - }, - }); - - return ( - - {categoryName} - - - {progressText} - - - - ); -}; - -export default CategoryProgressBar; diff --git a/components/stats/CategoryProgressBarList.tsx b/components/stats/CategoryProgressBarList.tsx deleted file mode 100644 index 42cfcf7..0000000 --- a/components/stats/CategoryProgressBarList.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import React, { useState } from 'react'; -import { View, Text, Button, StyleSheet, TouchableOpacity } from 'react-native'; -import CategoryProgressBar from './CategoryProgressBar'; - -interface CategoryItem { - name: string; - color: string; - maxValue: number; - currentValue: number; -} - -interface CategoryProgressBarListProps { - categories: CategoryItem[]; -} - -const MAX_VISIBLE_BARS = 4; - -const CategoryProgressBarList: React.FC = ({ categories }) => { - const [visibleBars, setVisibleBars] = useState(MAX_VISIBLE_BARS); - - const showMore = () => { - setVisibleBars(prevVisibleBars => prevVisibleBars + MAX_VISIBLE_BARS); - }; - - return ( - - {categories.slice(0, visibleBars).map((category, index) => ( - - ))} - {visibleBars < categories.length && ( - - Show More - - )} - - ); -}; - -const styles = StyleSheet.create({ - showMoreButton: { - backgroundColor: '#EF6C00', - padding: 10, - borderRadius: 5, - margin: 10, - alignItems: 'center', - }, - buttonText: { - color: 'white', - fontSize: 16, - fontWeight: 'bold', - }, -}); - -export default CategoryProgressBarList; \ No newline at end of file diff --git a/components/stats/FinancialAdvice.tsx b/components/stats/FinancialAdvice.tsx deleted file mode 100644 index 8f136ac..0000000 --- a/components/stats/FinancialAdvice.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { StyleSheet, View, Text } from 'react-native'; -import { useTheme } from '../../app/contexts/ThemeContext'; - -const FinancialAdvice = () => { - const tips = [ - "Maybe you shouldn't have bought that full-price video game. But who needs savings when you have high scores, right?", - "That daily gourmet coffee is essential, isn't it? Who needs a retirement fund when you've got caffeine!", - "Oh, another pair of designer shoes? Because the other twenty pairs just aren't enough.", - "A luxury car to drive two blocks? Obviously, walking is for peasants.", - "Sure, subscribe to all streaming services. Who needs to socialize outside when you can binge-watch shows alone forever?", - "A gym membership you never use? At least your wallet's getting a workout.", - "Booking another expensive vacation? It's not like you need to save for a rainy day or anything.", - "Another impulse purchase online? Because 'limited time offer' is definitely not a marketing tactic.", - "Eating out for every meal? Clearly, cooking at home is way too mainstream.", - "Upgrading to the latest phone model again? It must be tough having a phone that's 6 months old." - ]; - - const { colors } = useTheme(); - - const [tip, setTip] = useState(''); - - useEffect(() => { - // Change the tip every 10 seconds - const intervalId = setInterval(() => { - const randomTip = tips[Math.floor(Math.random() * tips.length)]; - setTip(randomTip); - }, 10000); - - // Clear the interval on component unmount - return () => clearInterval(intervalId); - }, [tips]); - - const styles = StyleSheet.create({ - container: { - margin: 10, - borderRadius: 5, - alignItems: 'center', - justifyContent: 'center' - }, - text: { - fontSize: 26, - color: colors.primaryText - }, - boldText: { - fontWeight: 'bold' - } - }); - - return ( - - - {tip} - - - ); -}; - -export default FinancialAdvice; diff --git a/components/stats/Graph.tsx b/components/stats/Graph.tsx deleted file mode 100644 index 6d737d8..0000000 --- a/components/stats/Graph.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Dimensions, View } from "react-native"; -import { PieChart } from "react-native-chart-kit"; -import { useTheme } from "../../app/contexts/ThemeContext"; -import useFetch from "../../hooks/useFetch"; - -const Graph = () => { - const {colors} = useTheme(); - - const {data} = useFetch({sql: "SELECT c.name AS name, c.color AS color, SUM(e.amount) as total FROM category c LEFT JOIN expense e ON e.category_guid = c.guid GROUP BY c.guid", args: []}); - const acctual_data = data.map(item => ({...item, legendFontColor: colors.primaryText, legendFontSize: 14})); - - return ( - - `rgba(255, 255, 255, ${opacity})`, - }} - backgroundColor="transparent" - accessor="total" - paddingLeft="15" - avoidFalseZero={true} - /> - - ); -} - -export default Graph; \ No newline at end of file diff --git a/components/stats/SavingsOverview.tsx b/components/stats/SavingsOverview.tsx deleted file mode 100644 index ea906a1..0000000 --- a/components/stats/SavingsOverview.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { Text, StyleSheet } from 'react-native'; -import { useTheme } from '../../app/contexts/ThemeContext'; -import useFetch from '../../hooks/useFetch'; -import { CategoryType } from '../../types/dbItems'; -import {useCategoryData} from '../../hooks/useCategoryData'; - -const styles = StyleSheet.create({ - container: { - margin: 10, - borderRadius: 5, - alignItems: 'center', - justifyContent: 'center' - }, - text: { - fontSize: 26, - color: `black` - }, - boldText: { - fontWeight: 'bold' - }, - negativeText: { - color: 'red', - }, - positiveText: { - color: 'green', - }, -}); - -interface BudgetTotalProps { - goodColor?: string; - badColor?: string; -} - -const BudgetTotal: React.FC = ({ goodColor = 'green', badColor = 'red' }) => { - const { colors } = useTheme(); - const { data, isLoading } = useCategoryData(CategoryType.SAVING); - - const { total, expenseTotal } = data; - - const remaining = total - expenseTotal; - - if (isLoading) { - return Loading...; - } - - return ( - - {remaining >= 0 ? ( - <> - You have saved {expenseTotal.toFixed(2)}€ out of your Goal of {total.toFixed(2)}€ - - ) : ( - <> - You have surpassed your Savings Goal of {total.toFixed(2)}€ by {Math.abs(remaining).toFixed(2)}€ - - )} - - ); -}; - -export default BudgetTotal; \ No newline at end of file diff --git a/components/stats/Widget.tsx b/components/stats/Widget.tsx deleted file mode 100644 index 3162d62..0000000 --- a/components/stats/Widget.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React, { ReactNode } from 'react'; -import { View, StyleSheet, Text, Image } from 'react-native'; -import { useTheme } from '../../app/contexts/ThemeContext'; - -interface WidgetProps { - title?: string; - text?: string; - children?: ReactNode; - image?: any; - backgroundColor?: string; -} - -const Widget: React.FC = ({ title, text, children, image, backgroundColor }) => { - const { colors } = useTheme(); - - - const actualBackgroundColor = backgroundColor ? backgroundColor : colors.widgetBackgroundColor; - - const styles = StyleSheet.create({ - widgetContainer: { - backgroundColor: actualBackgroundColor, - borderColor: colors.widgetBorderColor, - borderRadius: 5, - padding: 16, - marginVertical: 8, - marginHorizontal: 10, - shadowColor: '#000', - shadowOffset: { - width: 0, - height: 1, - }, - shadowOpacity: 0.22, - shadowRadius: 2.22, - elevation: 3, - }, - widgetTitle: { - color: colors.primaryText, - fontSize: 26, - fontWeight: 'bold', - marginBottom: 8, - textAlign: 'center', - }, - widgetText: { - color: colors.primaryText, - fontSize: 16, - marginBottom: 8, - textAlign: 'center', - }, - imageStyle: { - width: '100%', - height: 500, - borderRadius: 5, - marginBottom: 8, - }, - }); - - return ( - - {!!title && {title}} - {!!text && {text}} - {!!image && } - {children} - - ); -}; - -export default Widget; \ No newline at end of file diff --git a/constants/colors.ts b/constants/colors.ts index a707f73..6b8937d 100644 --- a/constants/colors.ts +++ b/constants/colors.ts @@ -12,9 +12,6 @@ export default { elementDefaultColor: "#E0E0E0", elementSelectedColor: "#9E9E9E", accentColor: "#EF6C00", - - widgetBackgroundColor: "#F7F7F7", - widgetBorderColor: "#E0E0E0", }, dark: { primaryText: "#FFFFFF", @@ -29,8 +26,5 @@ export default { elementDefaultColor: "#535353", elementSelectedColor: "#B3B3B3", accentColor: "#EF6C00", - - widgetBackgroundColor: "#252525", - widgetBorderColor: "#535353", } } \ No newline at end of file diff --git a/hooks/useCategoryData.ts b/hooks/useCategoryData.ts deleted file mode 100644 index 72cbe8b..0000000 --- a/hooks/useCategoryData.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { useState, useEffect } from 'react'; -import useFetch from './useFetch'; -import { CategoryType } from '../types/dbItems'; - -export const useCategoryData = (CategoryType: string) => { - const [data, setData] = useState({ total: 0, expenseTotal: 0 }); - const [isLoading, setLoading] = useState(true); - - const categoryQuery = { - sql: `SELECT SUM(allocated_amount) as total FROM category WHERE type = '${CategoryType.toString()}'`, - args: [] - }; - - const expenseQuery = { - sql: `SELECT SUM(e.amount) as total FROM expense e JOIN category c ON e.category_guid = c.guid WHERE c.type = '${CategoryType.toString()}'`, - args: [] - }; - - const { data: categoryData, isLoading: categoryLoading } = useFetch(categoryQuery); - const { data: expenseData, isLoading: expenseLoading } = useFetch(expenseQuery); - - useEffect(() => { - if (categoryData && expenseData) { - setData({ - total: categoryData[0]?.total || 0, - expenseTotal: expenseData[0]?.total || 0 - }); - } - setLoading(categoryLoading || expenseLoading); - }, [categoryData, categoryLoading, expenseData, expenseLoading]); - - return { categoryData, expenseData, isLoading, data }; -}; \ No newline at end of file diff --git a/hooks/useFetch.ts b/hooks/useFetch.ts index a828d31..496beba 100644 --- a/hooks/useFetch.ts +++ b/hooks/useFetch.ts @@ -4,37 +4,14 @@ import { executeQuery } from "../services/database"; const useFetch = (query: Query) => { - const [fetchState, setFetchState] = useState<{ - data: {[column: string]: any;}[]; - isLoading: boolean; - isEmptyResult: boolean | undefined; - }>({ - data: [], - isLoading: false, - isEmptyResult: undefined - }); - - const setIsLoading = (isLoading: boolean) => { - setFetchState((prevState) => ( {...prevState, isLoading} )); - } - - const setData = (data: {[column: string]: any;}[]) => { - setFetchState((prevState) => ( {...prevState, data} )); - } - - const setIsEmptyResult = (isEmptyResult: boolean) => { - setFetchState((prevState) => ( {...prevState, isEmptyResult} )); - } - + const [isLoading, setIsLoading] = useState(false); + const [data, setData] = useState<{[column: string]: any;}[]>([]); const reFetch = () => { setIsLoading(true); executeQuery(query).then((result) => { if("rows" in result[0]) { setData(result[0]["rows"]); - if(result[0]["rows"].length == 0){ - setIsEmptyResult(true); - } } }).catch((error: any) => { console.error("Fetching data from database has failed: ", error); @@ -47,7 +24,7 @@ const useFetch = (query: Query) => { reFetch(); }, []) - return {...fetchState, reFetch}; + return {data, isLoading, reFetch}; } export default useFetch; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 20b4a11..d597893 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "dependencies": { "@expo/vector-icons": "^13.0.0", "@react-native-async-storage/async-storage": "1.18.2", - "@react-native-community/datetimepicker": "7.2.0", "@react-navigation/native": "^6.0.2", "expo": "~49.0.15", "expo-font": "~11.4.0", @@ -26,15 +25,11 @@ "react-dom": "18.2.0", "react-native": "0.72.6", "react-native-calendars": "^1.1303.0", - "react-native-chart-kit": "^6.12.0", "react-native-gesture-handler": "~2.12.0", - "react-native-reanimated": "~3.3.0", "react-native-safe-area-context": "4.6.3", "react-native-screens": "~3.22.0", - "react-native-svg": "13.9.0", "react-native-uuid": "^2.0.1", - "react-native-web": "~0.19.6", - "reanimated-color-picker": "^2.4.2" + "react-native-web": "~0.19.6" }, "devDependencies": { "@babel/core": "^7.20.0", @@ -79,19 +74,19 @@ } }, "node_modules/@babel/core": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", - "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.6.tgz", + "integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.23.5", "@babel/generator": "^7.23.6", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.7", + "@babel/helpers": "^7.23.6", "@babel/parser": "^7.23.6", "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", + "@babel/traverse": "^7.23.6", "@babel/types": "^7.23.6", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -159,9 +154,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.7.tgz", - "integrity": "sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.6.tgz", + "integrity": "sha512-cBXU1vZni/CpGF29iTu4YRbOZt3Wat6zCoMDxRF1MayiEc4URxOj31tT65HUM0CRpMowA3HCJaAOVOUnMf96cw==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", @@ -404,12 +399,12 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.7.tgz", - "integrity": "sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.6.tgz", + "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==", "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", + "@babel/traverse": "^7.23.6", "@babel/types": "^7.23.6" }, "engines": { @@ -471,9 +466,9 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.7.tgz", - "integrity": "sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz", + "integrity": "sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-plugin-utils": "^7.22.5" @@ -520,12 +515,15 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.7.tgz", - "integrity": "sha512-b1s5JyeMvqj7d9m9KhJNHKc18gEJiSyVzVX3bwbiPalQBQpuvfPh6lA9F7Kk/dWH0TIiXRpB9yicwijY6buPng==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.6.tgz", + "integrity": "sha512-D7Ccq9LfkBFnow3azZGJvZYgcfeqAw3I1e5LoTpj6UKIFQilh8yqXsIGcRIqbBdsPWIz+Ze7ZZfggSj62Qp+Fg==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.23.7", + "@babel/helper-create-class-features-plugin": "^7.23.6", "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", "@babel/plugin-syntax-decorators": "^7.23.3" }, "engines": { @@ -975,9 +973,9 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.7.tgz", - "integrity": "sha512-PdxEpL71bJp1byMG0va5gwQcXHxuEYC/BgI/e88mGTtohbZN28O5Yit0Plkkm/dBzCF/BxmbNcses1RH1T+urA==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.4.tgz", + "integrity": "sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-plugin-utils": "^7.22.5", @@ -1417,20 +1415,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-object-assign": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.23.3.tgz", - "integrity": "sha512-TPJ6O7gVC2rlQH2hvQGRH273G1xdoloCj9Pc07Q7JbIZYDi+Sv5gaE2fu+r5E7qK4zyt6vj0FbZaZTRU5C3OMA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-object-rest-spread": { "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", @@ -1645,15 +1629,15 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.7.tgz", - "integrity": "sha512-fa0hnfmiXc9fq/weK34MUV0drz2pOL/vfKWvN7Qw127hiUPabFCUMgAbYWcchRzMJit4o5ARsK/s+5h0249pLw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.6.tgz", + "integrity": "sha512-kF1Zg62aPseQ11orDhFRw+aPG/eynNQtI+TyY+m33qJa2cJ5EEvza2P2BNTIA9E5MyqFABHEyY6CPHwgdy9aNg==", "dependencies": { "@babel/helper-module-imports": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.7", - "babel-plugin-polyfill-corejs3": "^0.8.7", - "babel-plugin-polyfill-regenerator": "^0.5.4", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", "semver": "^6.3.1" }, "engines": { @@ -1811,9 +1795,9 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.7.tgz", - "integrity": "sha512-SY27X/GtTz/L4UryMNJ6p4fH4nsgWbz84y9FE0bQeWJP6O5BhgVCt53CotQKHCOeXJel8VyhlhujhlltKms/CA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.6.tgz", + "integrity": "sha512-2XPn/BqKkZCpzYhUUNZ1ssXw7DcXfKQEjv/uXZUXgaebCMYmkEsfZ2yY+vv+xtXv50WmL5SGhyB6/xsWxIvvOQ==", "dependencies": { "@babel/compat-data": "^7.23.5", "@babel/helper-compilation-targets": "^7.23.6", @@ -1821,7 +1805,7 @@ "@babel/helper-validator-option": "^7.23.5", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", @@ -1842,7 +1826,7 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.23.3", - "@babel/plugin-transform-async-generator-functions": "^7.23.7", + "@babel/plugin-transform-async-generator-functions": "^7.23.4", "@babel/plugin-transform-async-to-generator": "^7.23.3", "@babel/plugin-transform-block-scoped-functions": "^7.23.3", "@babel/plugin-transform-block-scoping": "^7.23.4", @@ -1890,9 +1874,9 @@ "@babel/plugin-transform-unicode-regex": "^7.23.3", "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.7", - "babel-plugin-polyfill-corejs3": "^0.8.7", - "babel-plugin-polyfill-regenerator": "^0.5.4", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", "core-js-compat": "^3.31.0", "semver": "^6.3.1" }, @@ -1951,14 +1935,14 @@ } }, "node_modules/@babel/register": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.23.7.tgz", - "integrity": "sha512-EjJeB6+kvpk+Y5DAkEAmbOBEFkh9OASx0huoEkqYTFxAZHzOAX2Oh5uwAUuL2rUddqfM0SA+KPXV2TbzoZ2kvQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.22.15.tgz", + "integrity": "sha512-V3Q3EqoQdn65RCgTLwauZaTfd1ShhwPmbBv+1dkZV/HpCGMKVyn6oFcRlI7RaKqiDQjX2Qd3AuoEguBgdjIKlg==", "dependencies": { "clone-deep": "^4.0.1", "find-cache-dir": "^2.0.0", "make-dir": "^2.1.0", - "pirates": "^4.0.6", + "pirates": "^4.0.5", "source-map-support": "^0.5.16" }, "engines": { @@ -2003,9 +1987,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.7.tgz", - "integrity": "sha512-w06OXVOFso7LcbzMiDGt+3X7Rh7Ho8MmgPoWU3rarH+8upf+wSU/grlGbWzQyr3DkdN6ZeuMFjpdwW0Q+HxobA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", + "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2027,9 +2011,9 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", - "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", "dependencies": { "@babel/code-frame": "^7.23.5", "@babel/generator": "^7.23.6", @@ -3363,95 +3347,6 @@ "@hapi/hoek": "^9.0.0" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -4364,15 +4259,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "optional": true, - "engines": { - "node": ">=14" - } - }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz", @@ -6373,14 +6259,6 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, - "node_modules/@react-native-community/datetimepicker": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-7.2.0.tgz", - "integrity": "sha512-dO1sQy83M/EvnHE2egto05iwXZX7EYn5f/VDMp6afZFRFXRiRo7CzB3VFg4B55gJRJMNBv06NYMLPM3SlpnEGQ==", - "dependencies": { - "invariant": "^2.2.4" - } - }, "node_modules/@react-native/assets-registry": { "version": "0.72.0", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.72.0.tgz", @@ -6608,9 +6486,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", - "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" @@ -6668,9 +6546,9 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, "node_modules/@types/node": { - "version": "20.10.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.7.tgz", - "integrity": "sha512-fRbIKb8C/Y2lXxB5eVMj4IU7xpdox0Lh8bUPEdtLysaylsml1hOOx1+STloRs/B9nf7C6kPRmmg/V7aQW7usNg==", + "version": "20.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", + "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", "dependencies": { "undici-types": "~5.26.4" } @@ -6682,14 +6560,14 @@ "dev": true }, "node_modules/@types/qs": { - "version": "6.9.11", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", - "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==" + "version": "6.9.10", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", + "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==" }, "node_modules/@types/react": { - "version": "18.2.47", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.47.tgz", - "integrity": "sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==", + "version": "18.2.45", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.45.tgz", + "integrity": "sha512-TtAxCNrlrBp8GoeEp1npd5g+d/OejJHFxS3OWmrPBMFaVQMSN0OFySozJio5BHxTuTeug00AVXVAjfDSfk+lUg==", "dev": true, "dependencies": { "@types/prop-types": "*", @@ -6796,9 +6674,9 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "bin": { "acorn": "bin/acorn" }, @@ -7507,11 +7385,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, "node_modules/bplist-creator": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", @@ -7780,9 +7653,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001576", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz", - "integrity": "sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==", + "version": "1.0.30001570", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz", + "integrity": "sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==", "funding": [ { "type": "opencollective", @@ -8147,9 +8020,9 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/core-js-compat": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.0.tgz", - "integrity": "sha512-5blwFAddknKeNgsjBzilkdQ0+YK8L1PfqPYq40NOYMYFSS38qj+hpTcLLWwpIwA2A5bje/x5jmVn2tzUMg9IVw==", + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.34.0.tgz", + "integrity": "sha512-4ZIyeNbW/Cn1wkMMDy+mvrRUxrwFNjKwbhCfQpDd+eLgYipDqp8oGFGtLmhh18EDPKA0g3VUBYOxQGGwvWLVpA==", "dependencies": { "browserslist": "^4.22.2" }, @@ -8335,44 +8208,6 @@ "hyphenate-style-name": "^1.0.3" } }, - "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, "node_modules/cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -8662,30 +8497,6 @@ "node": ">=8" } }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, "node_modules/domexception": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", @@ -8699,33 +8510,6 @@ "node": ">=12" } }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, "node_modules/dotenv": { "version": "16.0.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", @@ -8742,20 +8526,15 @@ "node": ">=12" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.623", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.623.tgz", - "integrity": "sha512-lKoz10iCYlP1WtRYdh5MvocQPWVRoI7ysp6qf18bmeBgR8abE6+I2CsfyNKztRDZvhdWc+krKT6wS7Neg8sw3A==" + "version": "1.4.615", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.615.tgz", + "integrity": "sha512-/bKPPcgZVUziECqDc+0HkT87+0zhaWSZHNXqF8FLd2lQcptpmUFwoCSWjCdOng9Gdq+afKArPdEg/0ZW461Eng==" }, "node_modules/emittery": { "version": "0.13.1", @@ -8794,6 +8573,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, "engines": { "node": ">=0.12" }, @@ -9645,86 +9425,6 @@ "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz", "integrity": "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==" }, - "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/foreground-child/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/foreground-child/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/foreground-child/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "engines": { - "node": ">=8" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/form-data": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", @@ -10203,9 +9903,9 @@ } }, "node_modules/image-size": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz", - "integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", + "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", "dependencies": { "queue": "6.0.2" }, @@ -10213,7 +9913,7 @@ "image-size": "bin/image-size.js" }, "engines": { - "node": ">=16.x" + "node": ">=14.0.0" } }, "node_modules/immediate": { @@ -10695,23 +10395,6 @@ "node": ">=8" } }, - "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, "node_modules/jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", @@ -13776,11 +13459,6 @@ "resolved": "https://registry.npmjs.org/md5hex/-/md5hex-1.0.0.tgz", "integrity": "sha512-c2YOUbp33+6thdCUi34xIyOU/a7bvGKj/3DB1iaPMTuPHf/Q2d5s4sn1FaCOO43XkXggnb08y5W2PU8UNYNLKQ==" }, - "node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" - }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -14695,9 +14373,9 @@ } }, "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", "optional": true, "engines": { "node": "*" @@ -14984,17 +14662,6 @@ "node": ">=4" } }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, "node_modules/nullthrows": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", @@ -15348,37 +15015,6 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, - "node_modules/path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", - "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -15387,14 +15023,6 @@ "node": ">=8" } }, - "node_modules/paths-js": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/paths-js/-/paths-js-0.4.11.tgz", - "integrity": "sha512-3mqcLomDBXOo7Fo+UlaenG6f71bk1ZezPQy2JCmYHy2W2k5VKpP+Jbin9H0bjXynelTbglCqdFhSEkeIkKTYUA==", - "engines": { - "node": ">=0.11.0" - } - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -15595,15 +15223,10 @@ "node": ">=4.0.0" } }, - "node_modules/point-in-polygon": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.1.0.tgz", - "integrity": "sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==" - }, "node_modules/postcss": { - "version": "8.4.33", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", - "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", "funding": [ { "type": "opencollective", @@ -16122,21 +15745,6 @@ "moment": "^2.29.4" } }, - "node_modules/react-native-chart-kit": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/react-native-chart-kit/-/react-native-chart-kit-6.12.0.tgz", - "integrity": "sha512-nZLGyCFzZ7zmX0KjYeeSV1HKuPhl1wOMlTAqa0JhlyW62qV/1ZPXHgT8o9s8mkFaGxdqbspOeuaa6I9jUQDgnA==", - "dependencies": { - "lodash": "^4.17.13", - "paths-js": "^0.4.10", - "point-in-polygon": "^1.0.1" - }, - "peerDependencies": { - "react": "> 16.7.0", - "react-native": ">= 0.50.0", - "react-native-svg": "> 6.4.1" - } - }, "node_modules/react-native-gesture-handler": { "version": "2.12.1", "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.12.1.tgz", @@ -16153,27 +15761,6 @@ "react-native": "*" } }, - "node_modules/react-native-reanimated": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.3.0.tgz", - "integrity": "sha512-LzfpPZ1qXBGy5BcUHqw3pBC0qSd22qXS3t8hWSbozXNrBkzMhhOrcILE/nEg/PHpNNp1xvGOW8NwpAMF006roQ==", - "dependencies": { - "@babel/plugin-transform-object-assign": "^7.16.7", - "@babel/preset-typescript": "^7.16.7", - "convert-source-map": "^2.0.0", - "invariant": "^2.2.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0-0", - "@babel/plugin-proposal-optional-chaining": "^7.0.0-0", - "@babel/plugin-transform-arrow-functions": "^7.0.0-0", - "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", - "@babel/plugin-transform-template-literals": "^7.0.0-0", - "react": "*", - "react-native": "*" - } - }, "node_modules/react-native-safe-area-context": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.6.3.tgz", @@ -16196,19 +15783,6 @@ "react-native": "*" } }, - "node_modules/react-native-svg": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.9.0.tgz", - "integrity": "sha512-Ey18POH0dA0ob/QiwCBVrxIiwflhYuw0P0hBlOHeY4J5cdbs8ngdKHeWC/Kt9+ryP6fNoEQ1PUgPYw2Bs/rp5Q==", - "dependencies": { - "css-select": "^5.1.0", - "css-tree": "^1.1.3" - }, - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, "node_modules/react-native-swipe-gestures": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/react-native-swipe-gestures/-/react-native-swipe-gestures-1.0.5.tgz", @@ -16224,9 +15798,9 @@ } }, "node_modules/react-native-web": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.19.10.tgz", - "integrity": "sha512-IQoHiTQq8egBCVVwmTrYcFLgEFyb4LMZYEktHn4k22JMk9+QTCEz5WTfvr+jdNoeqj/7rtE81xgowKbfGO74qg==", + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.19.9.tgz", + "integrity": "sha512-m69arZbS6FV+BNSKE6R/NQwUX+CzxCkYM7AJlSLlS8dz3BDzlaxG8Bzqtzv/r3r1YFowhnZLBXVKIwovKDw49g==", "dependencies": { "@babel/runtime": "^7.18.6", "@react-native/normalize-color": "^2.1.0", @@ -16335,23 +15909,6 @@ "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==" }, - "node_modules/reanimated-color-picker": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/reanimated-color-picker/-/reanimated-color-picker-2.4.2.tgz", - "integrity": "sha512-UNw1jEEOjY2m6F/sI7/nZQwT+yl7kSxao9wJtdkHUsrmm66QRqWKku76/hZGXyl+wzdKk4yLmXMPaEaLq69GBg==", - "peerDependencies": { - "expo": ">=44.0.0", - "react": "*", - "react-native": "*", - "react-native-gesture-handler": ">=2.0.0", - "react-native-reanimated": "^2.0.0 || ^3.0.0" - }, - "peerDependenciesMeta": { - "expo": { - "optional": true - } - } - }, "node_modules/recast": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/recast/-/recast-0.21.5.tgz", @@ -17105,28 +16662,6 @@ "node": ">=8" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, "node_modules/string-width/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -17146,18 +16681,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -17211,13 +16734,13 @@ "integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==" }, "node_modules/sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", + "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", - "glob": "^10.3.10", + "glob": "7.1.6", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", @@ -17228,15 +16751,7 @@ "sucrase-node": "bin/sucrase-node" }, "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/sucrase/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" + "node": ">=8" } }, "node_modules/sucrase/node_modules/commander": { @@ -17247,49 +16762,6 @@ "node": ">= 6" } }, - "node_modules/sucrase/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sucrase/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sucrase/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/sudo-prompt": { "version": "8.2.5", "resolved": "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-8.2.5.tgz", @@ -17652,12 +17124,9 @@ } }, "node_modules/traverse": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz", - "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==", - "engines": { - "node": ">= 0.4" - }, + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", + "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -18135,53 +17604,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -18228,9 +17650,9 @@ } }, "node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "version": "8.15.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.15.1.tgz", + "integrity": "sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==", "engines": { "node": ">=10.0.0" }, diff --git a/package.json b/package.json index b86787c..7f833d1 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "dependencies": { "@expo/vector-icons": "^13.0.0", "@react-native-async-storage/async-storage": "1.18.2", - "@react-native-community/datetimepicker": "7.2.0", "@react-navigation/native": "^6.0.2", "expo": "~49.0.15", "expo-font": "~11.4.0", @@ -36,15 +35,11 @@ "react-dom": "18.2.0", "react-native": "0.72.6", "react-native-calendars": "^1.1303.0", - "react-native-chart-kit": "^6.12.0", "react-native-gesture-handler": "~2.12.0", - "react-native-reanimated": "~3.3.0", "react-native-safe-area-context": "4.6.3", "react-native-screens": "~3.22.0", - "react-native-svg": "13.9.0", "react-native-uuid": "^2.0.1", - "react-native-web": "~0.19.6", - "reanimated-color-picker": "^2.4.2" + "react-native-web": "~0.19.6" }, "devDependencies": { "@babel/core": "^7.20.0", diff --git a/services/DebugMenu.tsx b/services/DebugMenu.tsx deleted file mode 100644 index ff728ff..0000000 --- a/services/DebugMenu.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import React from 'react'; -import { View, Button, Alert } from 'react-native'; -import { addCategory, addExpense, deleteExpenses, deleteCategories, DEV_populateDatabase, deleteDatabase } from './database'; -import uuid from 'react-native-uuid'; -import { CategoryType } from '../types/dbItems'; - -const randomColors = ["red", "blue", "green", "purple", "yellow"]; - -const getRandomColor = () => { - return randomColors[Math.floor(Math.random() * randomColors.length)]; -}; - -const getRandomName = () => { - return `RandomName-${Math.floor(Math.random() * 1000)}`; -}; - -const getRandomNumber = () => { - return Math.floor(Math.random() * 1000); -}; - -const DebugMenu = () => { - - const deleteDBFile = () => { - console.warn("Deleting DB. App Restart is required") - return deleteDatabase(); - } - - const handleNukeDatabase = () => { - return deleteExpenses(), deleteCategories() - }; - - const handlePopulateDatabase = () => { - return DEV_populateDatabase() - }; - - const handleDeleteExpenses = () => { - return deleteExpenses(); - } - const handleDeleteCategories = () => { - return deleteCategories(); - } - -//for some reason this function does not work - const handleAddCategory = () => { - const name = getRandomName(); - const color = getRandomColor(); - const allocated_amount = getRandomNumber(); - const type = "expense"; - - addCategory(name, color, CategoryType.EXPENSE, allocated_amount) - .then(() => Alert.alert("Category Added", `Name: ${name}, Color: ${color}`)) - .catch((error: any) => console.error("Error adding category: ", error)); - }; - -//for some reason this function does not work - const handleAddExpense = () => { - const name = getRandomName(); - const categoryGuid = uuid.v4().toString(); - const datetime = new Date().toISOString(); - const amount = Math.floor(Math.random() * 1000); - - addExpense(name, categoryGuid, datetime, amount) - .then(() => Alert.alert("Expense Added", `Name: ${name}, Amount: ${amount}`)) - .catch((error: any) => console.error("Error adding expense: ", error)); - }; - - return ( - -