everything refactored
This commit is contained in:
parent
0240eb2562
commit
62e71d1b49
10 changed files with 407 additions and 50 deletions
38
components/stats/BudgetOverview.tsx
Normal file
38
components/stats/BudgetOverview.tsx
Normal file
|
|
@ -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<StatsBudgetProps> = ({ 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 (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.text}>
|
||||
You have spent <Text style={styles.boldText}>{spent.toFixed(2)}€</Text> out of your budget of <Text style={styles.boldText}>{budget.toFixed(2)}€</Text>.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default BudgetOverview
|
||||
38
components/stats/BudgetRemaining.tsx
Normal file
38
components/stats/BudgetRemaining.tsx
Normal file
|
|
@ -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<BudgetRemainingProps> = ({ 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 (
|
||||
<Text style={styles.text}>
|
||||
You have <Text style={styles.boldText}>{remaining.toFixed(2)}€</Text> left.
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
export default BudgetRemaining;
|
||||
69
components/stats/CategoryProgressBar.tsx
Normal file
69
components/stats/CategoryProgressBar.tsx
Normal file
|
|
@ -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<CategoryProgressBarProps> = ({
|
||||
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 (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.categoryName}>{categoryName}</Text>
|
||||
<View style={styles.progressBarContainer}>
|
||||
<View style={dynamicStyles.progressBarFill}>
|
||||
<Text style={dynamicStyles.progressText}>{progressText}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default CategoryProgressBar;
|
||||
61
components/stats/CategoryProgressBarList.tsx
Normal file
61
components/stats/CategoryProgressBarList.tsx
Normal file
|
|
@ -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<CategoryProgressBarListProps> = ({ categories }) => {
|
||||
const [visibleBars, setVisibleBars] = useState(MAX_VISIBLE_BARS);
|
||||
|
||||
const showMore = () => {
|
||||
setVisibleBars(prevVisibleBars => prevVisibleBars + MAX_VISIBLE_BARS);
|
||||
};
|
||||
|
||||
return (
|
||||
<View>
|
||||
{categories.slice(0, visibleBars).map((category, index) => (
|
||||
<CategoryProgressBar
|
||||
key={index}
|
||||
categoryName={category.name}
|
||||
color={category.color}
|
||||
maxValue={category.maxValue}
|
||||
currentValue={category.currentValue}
|
||||
/>
|
||||
))}
|
||||
{visibleBars < categories.length && (
|
||||
<TouchableOpacity style={styles.showMoreButton} onPress={showMore}>
|
||||
<Text style={styles.buttonText}>Show More</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
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;
|
||||
1
components/stats/PieChart.tsx
Normal file
1
components/stats/PieChart.tsx
Normal file
|
|
@ -0,0 +1 @@
|
|||
//honestly just fuck graphs
|
||||
63
components/stats/Widget.tsx
Normal file
63
components/stats/Widget.tsx
Normal file
|
|
@ -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?: string;
|
||||
}
|
||||
|
||||
const Widget: React.FC<WidgetProps> = ({ 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 (
|
||||
<View style={styles.widgetContainer}>
|
||||
{!!title && <Text style={styles.widgetTitle}>{title}</Text>}
|
||||
{!!text && <Text style={styles.widgetText}>{text}</Text>}
|
||||
{!!image && <Image source={{ uri: image }} style={styles.imageStyle} />}
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default Widget;
|
||||
Reference in a new issue