324 lines
9.3 KiB
JavaScript
324 lines
9.3 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import { View, StyleSheet, Dimensions, Text, FlatList } from 'react-native';
|
|
import * as SQLite from 'expo-sqlite';
|
|
import { LineChart } from 'react-native-chart-kit';
|
|
import { Modal, TouchableOpacity } from 'react-native';
|
|
import moment from 'moment';
|
|
import 'moment/locale/it'; // Import Italian locale for moment
|
|
|
|
const VisualizzaDati = () => {
|
|
const [data, setData] = useState([]);
|
|
const [selectedTransactions, setSelectedTransactions] = useState([]);
|
|
const [modalVisible, setModalVisible] = useState(false);
|
|
const [selectedDate, setSelectedDate] = useState('');
|
|
const [currentWeek, setCurrentWeek] = useState(moment().startOf('week'));
|
|
|
|
useEffect(() => {
|
|
const interval = setInterval(() => {
|
|
fetchData();
|
|
}, 1000); // Aggiorna ogni 1 secondi
|
|
|
|
return () => clearInterval(interval); // Pulisce l'intervallo quando il componente viene smontato
|
|
}, []);
|
|
|
|
async function fetchData() {
|
|
try {
|
|
const db = await SQLite.openDatabaseAsync('moneyAppDB');
|
|
|
|
const result = await db.getAllAsync('SELECT * FROM transactions');
|
|
const fetchedData = [];
|
|
for (const row of result) {
|
|
fetchedData.push(row);
|
|
}
|
|
|
|
// Raggruppa i dati per data e calcola la somma degli importi per il grafico
|
|
const groupedData = fetchedData.reduce((acc, curr) => {
|
|
const date = curr.date;
|
|
if (!acc[date]) {
|
|
acc[date] = 0;
|
|
}
|
|
acc[date] += curr.amount;
|
|
return acc;
|
|
}, {});
|
|
|
|
// Trasforma l'oggetto raggruppato in un array di oggetti e ordina per data
|
|
const chartDataArray = Object.keys(groupedData)
|
|
.map(date => ({
|
|
date,
|
|
amount: groupedData[date],
|
|
}))
|
|
.sort((a, b) => new Date(a.date.split('-').reverse().join('-')) - new Date(b.date.split('-').reverse().join('-')));
|
|
|
|
setData(chartDataArray);
|
|
} catch (error) {
|
|
console.error('Error fetching data:', error);
|
|
}
|
|
}
|
|
|
|
const getWeekData = () => {
|
|
const startOfWeek = currentWeek.clone().startOf('week');
|
|
const endOfWeek = currentWeek.clone().endOf('week');
|
|
const weekDates = [];
|
|
for (let i = 0; i < 7; i++) {
|
|
weekDates.push(startOfWeek.clone().add(i, 'days').format('DD-MM-YYYY'));
|
|
}
|
|
const weekData = weekDates.map(date => {
|
|
const item = data.find(d => d.date === date);
|
|
return {
|
|
date,
|
|
amount: item ? item.amount : 0,
|
|
};
|
|
});
|
|
return weekData;
|
|
};
|
|
|
|
const getCurrentWeekText = () => {
|
|
moment.locale('it'); // Set moment locale to Italian
|
|
const startOfWeek = currentWeek.clone().startOf('week').format('DD MMMM');
|
|
const endOfWeek = currentWeek.clone().endOf('week').format('DD MMMM');
|
|
return `${startOfWeek} al ${endOfWeek}`;
|
|
};
|
|
|
|
const chartData = {
|
|
labels: getWeekData().map(item => item.date),
|
|
datasets: [
|
|
{
|
|
data: getWeekData().map(item => item.amount),
|
|
},
|
|
],
|
|
};
|
|
|
|
const handleDataPointClick = async (dataPoint) => {
|
|
const date = chartData.labels[dataPoint.index];
|
|
setSelectedDate(date);
|
|
try {
|
|
const db = await SQLite.openDatabaseAsync('moneyAppDB');
|
|
const result = await db.getAllAsync(`SELECT * FROM transactions WHERE date = ?`, [date]);
|
|
setSelectedTransactions(result);
|
|
setModalVisible(true);
|
|
} catch (error) {
|
|
console.error('Error fetching transactions for selected date:', error);
|
|
}
|
|
};
|
|
|
|
const handlePrevWeek = () => {
|
|
setCurrentWeek(currentWeek.clone().subtract(1, 'week'));
|
|
};
|
|
|
|
const handleNextWeek = () => {
|
|
setCurrentWeek(currentWeek.clone().add(1, 'week'));
|
|
};
|
|
|
|
const getTotalForWeek = () => {
|
|
const weekData = getWeekData();
|
|
const total = weekData.reduce((acc, curr) => acc + curr.amount, 0);
|
|
return total;
|
|
};
|
|
|
|
return (
|
|
<FlatList
|
|
data={[{ key: 'content' }]}
|
|
renderItem={() => (
|
|
<View style={styles.container}>
|
|
{data.length === 0 ? (
|
|
<Text style={styles.noDataText}>Nessun dato disponibile</Text>
|
|
) : (
|
|
<>
|
|
<Text style={styles.weekText}>{getCurrentWeekText()}</Text>
|
|
<Text style={[styles.totalText, { color: getTotalForWeek() >= 0 ? 'green' : 'red' }]}>
|
|
Totale: {getTotalForWeek().toFixed(2)} €
|
|
</Text>
|
|
<LineChart
|
|
bezier
|
|
data={chartData}
|
|
width={Dimensions.get('window').width - 20} // from react-native
|
|
height={300}
|
|
verticalLabelRotation={30}
|
|
yAxisLabel="€"
|
|
chartConfig={{
|
|
backgroundColor: '#fff',
|
|
backgroundGradientFrom: '#000',
|
|
backgroundGradientTo: '#000',
|
|
decimalPlaces: 2, // optional, defaults to 2dp
|
|
color: (opacity = 1) => `#f57242`,
|
|
labelColor: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`,
|
|
style: {
|
|
borderRadius: 10,
|
|
},
|
|
propsForDots: {
|
|
r: '6',
|
|
strokeWidth: '3',
|
|
stroke: '#3956e6',
|
|
},
|
|
}}
|
|
style={{
|
|
borderRadius: 15,
|
|
}}
|
|
onDataPointClick={handleDataPointClick}
|
|
/>
|
|
|
|
<View style={styles.buttonContainer}>
|
|
<TouchableOpacity
|
|
style={styles.navButton}
|
|
onPress={handlePrevWeek}
|
|
>
|
|
<Text style={styles.navButtonText}>Settimana Precedente</Text>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity
|
|
style={styles.navButton}
|
|
onPress={handleNextWeek}
|
|
>
|
|
<Text style={styles.navButtonText}>Settimana Successiva</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
<Modal
|
|
animationType="slide"
|
|
transparent={true}
|
|
visible={modalVisible}
|
|
onRequestClose={() => setModalVisible(false)}
|
|
>
|
|
<View style={styles.centeredView}>
|
|
<View style={styles.modalView}>
|
|
<Text style={styles.modalTitle}>Transazioni del {selectedDate}</Text>
|
|
<FlatList
|
|
data={selectedTransactions}
|
|
keyExtractor={(item, index) => index.toString()}
|
|
renderItem={({ item }) => (
|
|
<View style={styles.transactionItem}>
|
|
<View><Text style={styles.transactionDescription}>{item.description}</Text></View>
|
|
<View>
|
|
<Text style={[styles.transactionAmount, { color: item.type === 'expense' ? 'red' : 'green' }]}>
|
|
{item.type === 'expense' ? '-' : '+'}{Math.abs(item.amount).toFixed(2)} €
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
)}
|
|
/>
|
|
<TouchableOpacity
|
|
style={styles.closeButton}
|
|
onPress={() => setModalVisible(false)}
|
|
>
|
|
<Text style={styles.closeButtonText}>Chiudi</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
</Modal>
|
|
</>
|
|
)}
|
|
</View>
|
|
)}
|
|
keyExtractor={item => item.key}
|
|
/>
|
|
);
|
|
};
|
|
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
marginTop: 20,
|
|
padding: 10,
|
|
},
|
|
buttonContainer: {
|
|
justifyContent: 'space-between',
|
|
flexDirection: 'row',
|
|
marginVertical: 10,
|
|
},
|
|
noDataText: {
|
|
color: '#000',
|
|
fontSize: 16,
|
|
textAlign: 'center',
|
|
marginTop: 20,
|
|
},
|
|
transactionsContainer: {
|
|
},
|
|
transactionsTitle: {
|
|
fontSize: 18,
|
|
fontWeight: 'bold',
|
|
color: '#fff',
|
|
marginVertical: 15,
|
|
textAlign: 'center',
|
|
},
|
|
transactionItem: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
padding: 15,
|
|
marginVertical: 5,
|
|
borderRadius: 10,
|
|
width: '100%',
|
|
backgroundColor: '#1a1a1a',
|
|
},
|
|
transactionDate: {
|
|
color: '#fff',
|
|
fontSize: 14,
|
|
},
|
|
transactionDescription: {
|
|
color: '#fff',
|
|
fontSize: 16,
|
|
},
|
|
transactionAmount: {
|
|
color: 'red',
|
|
fontSize: 16,
|
|
fontWeight: 'bold',
|
|
},
|
|
centeredView: {
|
|
flex: 1,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
marginTop: 22,
|
|
},
|
|
modalView: {
|
|
margin: 20,
|
|
height: 500,
|
|
backgroundColor: '#000',
|
|
borderRadius: 20,
|
|
borderColor: '#3c3c3c',
|
|
borderWidth: 2,
|
|
padding: 20,
|
|
alignItems: 'center',
|
|
},
|
|
modalTitle: {
|
|
fontSize: 18,
|
|
fontWeight: 'bold',
|
|
marginBottom: 15,
|
|
textAlign: 'center',
|
|
color: '#fff'
|
|
},
|
|
navButton: {
|
|
padding: 10,
|
|
borderRadius: 5,
|
|
margin: 2,
|
|
backgroundColor: '#f57242',
|
|
},
|
|
navButtonText: {
|
|
color: '#000',
|
|
fontSize: 16,
|
|
},
|
|
closeButton: {
|
|
marginTop: 20,
|
|
padding: 10,
|
|
borderRadius: 5,
|
|
backgroundColor: '#fff',
|
|
},
|
|
closeButtonText: {
|
|
color: '#000',
|
|
fontSize: 16,
|
|
},
|
|
weekText: {
|
|
color: '#fff',
|
|
fontSize: 22,
|
|
textAlign: 'center',
|
|
paddingBottom: 20
|
|
},
|
|
totalText: {
|
|
fontSize: 20,
|
|
textAlign: 'center',
|
|
marginBottom: 20,
|
|
},
|
|
});
|
|
|
|
export default VisualizzaDati;
|
|
|
|
|
|
|