diff --git a/app/(tabs)/stats/index.tsx b/app/(tabs)/stats/index.tsx
index 9dd775a..9a2033a 100644
--- a/app/(tabs)/stats/index.tsx
+++ b/app/(tabs)/stats/index.tsx
@@ -1,61 +1,69 @@
-import { Query } from 'expo-sqlite';
-import { StyleSheet, Text, View } from 'react-native';
-import { addCategory, deleteDatabase, deleteExpenses, executeQuery, initDatabase } from '../../../services/database';
+import React from 'react';
+import { StyleSheet, View, ScrollView } from 'react-native';
+import BudgetOverview from '../../../components/stats/BudgetOverview';
+import { useTheme } from '../../contexts/ThemeContext';
+import Widget from '../../../components/stats/Widget';
+import CategoryProgressBarList from '../../../components/stats/CategoryProgressBarList';
+import BudgetRemaining from '../../../components/stats/BudgetRemaining';
+import DebugMenu from '../../../services/DebugMenu';
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 BudgetData = [
+ { name: 'Utilities', color: '#20B2AA', maxValue: 80, currentValue: 46 },
+ { name: 'Food', color: '#FF6347', maxValue: 88, currentValue: 31 },
+ ];
+
+ const SavingsData = [
+ { name: 'Education', color: '#FF6347', maxValue: 135, currentValue: 0 },
+ { name: 'Rent', color: '#DA70D6', maxValue: 140, currentValue: 96 },
+ { name: 'Food', color: '#F08080', maxValue: 84, currentValue: 78 },
+ { name: 'Healthcare', color: '#20B2AA', maxValue: 134, currentValue: 48 },
+ { name: 'Healthcare', color: '#32CD32', maxValue: 119, currentValue: 69 },
+ { name: 'Clothing', color: '#32CD32', maxValue: 115, currentValue: 99 },
+ ];
+
+ const categoryData = [
+ { category: 'Food', value: 50 },
+ { category: 'Rent', value: 300 },
+ { category: 'Utilities', value: 100 },
+ ];
+
const styles = StyleSheet.create({
container: {
flex: 1,
- justifyContent: 'space-evenly',
+ backgroundColor: colors.backgroundColor,
+ marginTop: 50,
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/assets/images/8b14el.jpg b/assets/images/8b14el.jpg
new file mode 100644
index 0000000..3e1e0e6
Binary files /dev/null and b/assets/images/8b14el.jpg differ
diff --git a/components/stats/BudgetOverview.tsx b/components/stats/BudgetOverview.tsx
new file mode 100644
index 0000000..5339fb3
--- /dev/null
+++ b/components/stats/BudgetOverview.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import { useTheme } from '../../app/contexts/ThemeContext';
+
+interface StatsBudgetProps {
+ spent: number;
+ budget: number;
+}
+
+const BudgetOverview: React.FC = ({ spent, budget }) => {
+ const { colors } = useTheme();
+
+ const styles = StyleSheet.create({
+ container: {
+ margin: 10,
+ borderRadius: 5,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ text: {
+ fontSize: 26,
+ color: colors.primaryText,
+ },
+ boldText: {
+ fontWeight: 'bold',
+ },
+ });
+
+ return (
+
+
+ You have spent {spent.toFixed(2)}€ out of your budget of {budget.toFixed(2)}€.
+
+
+ );
+};
+
+export default BudgetOverview
diff --git a/components/stats/BudgetRemaining.tsx b/components/stats/BudgetRemaining.tsx
new file mode 100644
index 0000000..1eb038e
--- /dev/null
+++ b/components/stats/BudgetRemaining.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import { Text, StyleSheet } from 'react-native';
+import { useTheme } from '../../app/contexts/ThemeContext';
+
+interface BudgetRemainingProps {
+ budget: number;
+ spent: number;
+}
+
+const BudgetRemaining: React.FC = ({ budget, spent }) => {
+ const { colors, theme } = useTheme();
+
+ const remaining = budget - spent;
+
+ const styles = StyleSheet.create({
+ container: {
+ margin: 10,
+ borderRadius: 5,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ text: {
+ fontSize: 26,
+ color: colors.primaryText,
+ },
+ boldText: {
+ fontWeight: 'bold',
+ },
+ });
+
+ return (
+
+ You have {remaining.toFixed(2)}€ left.
+
+ );
+};
+
+export default BudgetRemaining;
diff --git a/components/stats/CategoryProgressBar.tsx b/components/stats/CategoryProgressBar.tsx
new file mode 100644
index 0000000..4e49975
--- /dev/null
+++ b/components/stats/CategoryProgressBar.tsx
@@ -0,0 +1,69 @@
+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
new file mode 100644
index 0000000..566f352
--- /dev/null
+++ b/components/stats/CategoryProgressBarList.tsx
@@ -0,0 +1,61 @@
+import React, { useState } from 'react';
+import { View, Text, Button, StyleSheet, TouchableOpacity } from 'react-native';
+import CategoryProgressBar from './CategoryProgressBar';
+import { useTheme } from '../../app/contexts/ThemeContext';
+
+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/PieChart.tsx b/components/stats/PieChart.tsx
new file mode 100644
index 0000000..f3fe67e
--- /dev/null
+++ b/components/stats/PieChart.tsx
@@ -0,0 +1 @@
+//honestly just fuck graphs
\ No newline at end of file
diff --git a/components/stats/Widget.tsx b/components/stats/Widget.tsx
new file mode 100644
index 0000000..153ed65
--- /dev/null
+++ b/components/stats/Widget.tsx
@@ -0,0 +1,63 @@
+import React, { ReactNode } from 'react';
+import { View, StyleSheet, Text, Image } from 'react-native'; // Add the missing import statement for Image
+import { useTheme } from '../../app/contexts/ThemeContext';
+
+interface WidgetProps {
+ title?: string;
+ text?: string;
+ children?: ReactNode;
+ image?: any;
+}
+
+const Widget: React.FC = ({ title, text, children, image }) => { // Add the 'image' prop to the destructuring
+ const { colors } = useTheme();
+
+ const styles = StyleSheet.create({
+ widgetContainer: {
+ backgroundColor: colors.widgetBackgroundColor,
+ 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: 200,
+ 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 6b8937d..a707f73 100644
--- a/constants/colors.ts
+++ b/constants/colors.ts
@@ -12,6 +12,9 @@ export default {
elementDefaultColor: "#E0E0E0",
elementSelectedColor: "#9E9E9E",
accentColor: "#EF6C00",
+
+ widgetBackgroundColor: "#F7F7F7",
+ widgetBorderColor: "#E0E0E0",
},
dark: {
primaryText: "#FFFFFF",
@@ -26,5 +29,8 @@ export default {
elementDefaultColor: "#535353",
elementSelectedColor: "#B3B3B3",
accentColor: "#EF6C00",
+
+ widgetBackgroundColor: "#252525",
+ widgetBorderColor: "#535353",
}
}
\ No newline at end of file
diff --git a/services/DebugMenu.tsx b/services/DebugMenu.tsx
new file mode 100644
index 0000000..896a667
--- /dev/null
+++ b/services/DebugMenu.tsx
@@ -0,0 +1,73 @@
+import React from 'react';
+import { View, Button, Alert } from 'react-native';
+import { addCategory, addExpense, deleteExpenses, deleteCategories, DEV_populateDatabase } from './database';
+import uuid from 'react-native-uuid';
+
+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 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, type, 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 (
+
+
+
+
+
+
+
+
+ );
+};
+
+export default DebugMenu;
\ No newline at end of file