diff --git a/app/(tabs)/stats/index.tsx b/app/(tabs)/stats/index.tsx
new file mode 100644
index 0000000..97a3b74
--- /dev/null
+++ b/app/(tabs)/stats/index.tsx
@@ -0,0 +1,52 @@
+import React from 'react';
+import { StyleSheet, View, ScrollView } from 'react-native';
+import BudgetTotal from '../../../components/stats/BudgetTotal';
+import { useTheme } from '../../contexts/ThemeContext';
+import Widget from '../../../components/stats/Widget';
+import DebugMenu from '../../../services/DebugMenu';
+import SavingsOverview from '../../../components/stats/SavingsOverview';
+import FinancialAdvice from '../../../components/stats/FinancialAdvice';
+import BudgetOverview from '../../../components/stats/BudgetOverview';
+
+export default function Page() {
+ const { colors } = useTheme();
+
+ // Mock data #TODO Database einbinden
+ // what to do when amount too small?
+
+ const spent = 120.75;
+ const budget = 696.96;
+
+
+
+ const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: colors.backgroundColor,
+ marginTop: 50,
+ alignItems: 'center',
+ },
+ });
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/components/stats/BudgetOverview.tsx b/components/stats/BudgetOverview.tsx
index 8cc5c6c..de40065 100644
--- a/components/stats/BudgetOverview.tsx
+++ b/components/stats/BudgetOverview.tsx
@@ -1,63 +1,56 @@
import React, { useState, useEffect } from 'react';
-import { View, Text, StyleSheet } from 'react-native';
+import { Text, StyleSheet } from 'react-native';
import { useTheme } from '../../app/contexts/ThemeContext';
import useFetch from '../../hooks/useFetch';
import { CategoryType } from '../../services/database';
+import {useCategoryData} from '../../hooks/useCategoryData';
-const BudgetOverview = () => {
+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 [spent, setSpent] = useState(0);
- const [budget, setBudget] = useState(0);
+ const { data, isLoading } = useCategoryData(CategoryType.EXPENSE);
- const spentQuery = {
- sql: `SELECT SUM(e.amount) as total FROM expense e LEFT JOIN category c ON e.category_guid = c.guid WHERE c.type = '${CategoryType.EXPENSE.toString()}'`,
- args: []
- };
+ const { total, expenseTotal } = data;
- const budgetQuery = {
- sql: `SELECT SUM(allocated_amount) as total FROM category WHERE type = '${CategoryType.EXPENSE.toString()}'`,
- args: []
- };
+ const remaining = total - expenseTotal;
- const { data: spentData, isLoading: spentLoading } = useFetch(spentQuery);
- const { data: budgetData, isLoading: budgetLoading } = useFetch(budgetQuery);
-
- useEffect(() => {
- if (spentData) {
- setSpent(spentData[0]?.total || 0);
- }
- if (budgetData) {
- setBudget(budgetData[0]?.total || 0);
- }
- }, [spentData, budgetData]);
-
- const styles = StyleSheet.create({
- container: {
- margin: 10,
- borderRadius: 5,
- alignItems: 'center',
- justifyContent: 'center'
- },
- text: {
- fontSize: 26,
- color: colors.primaryText
- },
- boldText: {
- fontWeight: 'bold'
- }
- });
-
- if (spentLoading || budgetLoading) {
+ if (isLoading) {
return Loading...;
}
return (
-
-
- You have spent {spent.toFixed(2)}€ out of your budget of {budget.toFixed(2)}€.
-
-
+
+ <>
+ You have spent {expenseTotal.toFixed(2)}€ out of your Budget of {total.toFixed(2)}€ .
+ >
+
);
};
-export default BudgetOverview;
+export default BudgetTotal;
\ No newline at end of file
diff --git a/components/stats/BudgetRemaining.tsx b/components/stats/BudgetRemaining.tsx
deleted file mode 100644
index 98a5cf0..0000000
--- a/components/stats/BudgetRemaining.tsx
+++ /dev/null
@@ -1,82 +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 '../../services/database';
-
-const styles = StyleSheet.create({
- container: {
- margin: 10,
- borderRadius: 5,
- alignItems: 'center',
- justifyContent: 'center'
- },
- text: {
- fontSize: 26,
- },
- boldText: {
- fontWeight: 'bold'
- },
- negativeText: {
- color: 'red',
- },
- positiveText: {
- color: 'green',
- },
-});
-
-
-interface BudgetRemainingProps {
- goodColor?: string;
- badColor?: string;
-}
-
-const BudgetRemaining: React.FC = ({ goodColor = 'green', badColor = 'red' }) => {
- const { colors } = useTheme();
- const [spent, setSpent] = useState(0);
- const [budget, setBudget] = useState(0);
-
- const spentQuery = {
- sql: "SELECT SUM(amount) as total FROM expense",
- args: []
- };
-
- const budgetQuery = {
- sql: `SELECT SUM(allocated_amount) as total FROM category WHERE type = '${CategoryType.EXPENSE.toString()}'`,
- args: []
- };
-
- const { data: spentData, isLoading: spentLoading } = useFetch(spentQuery);
- const { data: budgetData, isLoading: budgetLoading } = useFetch(budgetQuery);
-
- useEffect(() => {
- if (spentData) {
- setSpent(spentData[0]?.total || 0);
- }
- if (budgetData) {
- setBudget(budgetData[0]?.total || 0);
- }
- }, [spentData, budgetData]);
-
- const remaining = budget - spent;
-
- if (spentLoading || budgetLoading) {
- return Loading...;
- }
-
- return (
-
- {remaining >= 0 ? (
- <>
- Your remaining Budget is {remaining.toFixed(2)}€.
- >
- ) : (
- <>
- Your Budget is overspent by by -{Math.abs(remaining).toFixed(2)}€.
- >
- )}
-
- );
-};
-
-export default BudgetRemaining;
diff --git a/components/stats/BudgetTotal.tsx b/components/stats/BudgetTotal.tsx
new file mode 100644
index 0000000..6acfa6b
--- /dev/null
+++ b/components/stats/BudgetTotal.tsx
@@ -0,0 +1,62 @@
+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 '../../services/database';
+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/SavingsOverview.tsx b/components/stats/SavingsOverview.tsx
index 5162e75..064cf5e 100644
--- a/components/stats/SavingsOverview.tsx
+++ b/components/stats/SavingsOverview.tsx
@@ -1,63 +1,62 @@
import React, { useState, useEffect } from 'react';
-import { View, Text, StyleSheet } from 'react-native';
+import { Text, StyleSheet } from 'react-native';
import { useTheme } from '../../app/contexts/ThemeContext';
import useFetch from '../../hooks/useFetch';
import { CategoryType } from '../../services/database';
+import {useCategoryData} from '../../hooks/useCategoryData';
-const SavingsOverview = () => {
+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 [saved, setSaved] = useState(0);
- const [goal, setGoal] = useState(0);
+ const { data, isLoading } = useCategoryData(CategoryType.SAVING);
- const savedQuery = {
- sql: `SELECT SUM(e.amount) as total FROM expense e LEFT JOIN category c ON e.category_guid = c.guid WHERE c.type = '${CategoryType.SAVING.toString()}'`,
- args: []
- };
+ const { total, expenseTotal } = data;
- const goalQuery = {
- sql: `SELECT SUM(allocated_amount) as total FROM category WHERE type = '${CategoryType.SAVING.toString()}'`,
- args: []
- };
+ const remaining = total - expenseTotal;
- const { data: savedData, isLoading: savedLoading } = useFetch(savedQuery);
- const { data: goalData, isLoading: goalLoading } = useFetch(goalQuery);
-
- useEffect(() => {
- if (savedData) {
- setSaved(savedData[0]?.total || 0);
- }
- if (goalData) {
- setGoal(goalData[0]?.total || 0);
- }
- }, [savedData, goalData]);
-
- const styles = StyleSheet.create({
- container: {
- margin: 10,
- borderRadius: 5,
- alignItems: 'center',
- justifyContent: 'center'
- },
- text: {
- fontSize: 26,
- color: colors.primaryText
- },
- boldText: {
- fontWeight: 'bold'
- }
- });
-
- if (savedLoading || goalLoading) {
+ if (isLoading) {
return Loading...;
}
return (
-
-
- You have saved {saved.toFixed(2)}€ out of your goal of {goal.toFixed(2)}€.
-
-
+
+ {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 SavingsOverview;
\ No newline at end of file
+export default BudgetTotal;
\ No newline at end of file
diff --git a/hooks/useCategoryData.ts b/hooks/useCategoryData.ts
new file mode 100644
index 0000000..3939a53
--- /dev/null
+++ b/hooks/useCategoryData.ts
@@ -0,0 +1,33 @@
+import { useState, useEffect } from 'react';
+import useFetch from './useFetch';
+import { CategoryType } from '../services/database';
+
+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