Skip to content

Commit

Permalink
feat(Graph) : sentiment score graph visualize
Browse files Browse the repository at this point in the history
- Home 에서 사용하는 선택된 날짜 Context로 분리
- DB 스키마 수정
  • Loading branch information
kasterra committed Nov 13, 2023
1 parent 06bd3bc commit 3d2bc0b
Show file tree
Hide file tree
Showing 11 changed files with 298 additions and 110 deletions.
83 changes: 51 additions & 32 deletions src/components/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, {useState, useEffect, useCallback} from 'react';
import {StyleSheet, View, Text, TouchableOpacity} from 'react-native';
import {
formatDateToMonthYear,
formatDateToNumber,
getDaysOfMonth,
weekDaysList,
} from 'util/dateUtil';
Expand All @@ -11,59 +12,74 @@ import Diary from 'model/Diary';
import {useDatabase} from '@nozbe/watermelondb/hooks';
import {Q} from '@nozbe/watermelondb';
import {useIsFocused} from '@react-navigation/native';
import {
useSelectedDate,
useSelectedDateDispatch,
} from 'contexts/SelectedDateContext';

interface Props {
onDateClick: (date: Date) => void;
}

const Calendar = ({onDateClick}: Props) => {
const [currentDate, setCurrentDate] = useState<Date>(new Date());
const {
data: {selectedDate},
} = useSelectedDate();
const dispatch = useSelectedDateDispatch();
const [thisMonthDiaries, setThisMonthDiaries] = useState<Diary[]>([]);

const database = useDatabase();
const isFocused = useIsFocused();

const thisYear = currentDate.getFullYear();
const thisMonth = String(currentDate.getMonth() + 1).padStart(2, '0');

const fetchThisMonthDiaries = useCallback(async () => {
const dateString = `${thisYear}-${thisMonth}-__`;
const fetchCurrentMonthDiaries = useCallback(async () => {
const dayMonthStart = new Date(
selectedDate.getFullYear(),
selectedDate.getMonth(),
1,
0,
0,
0,
);
const dayMonthEnd = new Date(
selectedDate.getFullYear(),
selectedDate.getMonth() + 1,
0,
0,
0,
0,
);
let diaries: Diary[] = [];
try {
diaries = await database
.get<Diary>('diaries')
.query(Q.where('date', Q.like(dateString)));
.query(
Q.and(
Q.where('date', Q.gte(formatDateToNumber(dayMonthStart))),
Q.where('date', Q.lte(formatDateToNumber(dayMonthEnd))),
),
);
} catch (e) {
console.error('error fetching diary', e);
}
setThisMonthDiaries(diaries);
}, [database, thisMonth, thisYear]);
}, [database, selectedDate]);

useEffect(() => {
const loadDiaries = async () => {
await fetchThisMonthDiaries();
await fetchCurrentMonthDiaries();
};
loadDiaries();
}, [fetchThisMonthDiaries, isFocused]);
}, [fetchCurrentMonthDiaries, isFocused]);

const onPrevMonth = () => {
setCurrentDate(
new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1),
);
dispatch({type: 'PREV_MONTH'});
};

const onNextMonth = () => {
setCurrentDate(
new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1),
);
dispatch({type: 'NEXT_MONTH'});
};

useEffect(() => {
// 캘린더가 처음 렌더링될 때 현재 날짜로 설정합니다.
setCurrentDate(new Date());
}, []);

const daysOfMonth = getDaysOfMonth(currentDate);
const daysOfMonth = getDaysOfMonth(selectedDate);

return (
<View style={styles.container}>
Expand All @@ -72,7 +88,7 @@ const Calendar = ({onDateClick}: Props) => {
<LeftArrow width={40} height={40} />
</TouchableOpacity>
<Text style={styles.yearAndMonth}>
{formatDateToMonthYear(currentDate)}
{formatDateToMonthYear(selectedDate)}
</Text>
<TouchableOpacity key="nextButton" onPress={onNextMonth}>
<RightArrow width={40} height={40} />
Expand All @@ -95,8 +111,8 @@ const Calendar = ({onDateClick}: Props) => {
onPress={() =>
onDateClick(
new Date(
currentDate.getFullYear(),
currentDate.getMonth(),
selectedDate.getFullYear(),
selectedDate.getMonth(),
day,
),
)
Expand All @@ -105,13 +121,16 @@ const Calendar = ({onDateClick}: Props) => {
style={[
styles.dayText,
thisMonthDiaries &&
thisMonthDiaries.some(diary =>
new RegExp(
`${thisYear}-${thisMonth}-${String(day).padStart(
2,
'0',
)}`,
).test(diary.date),
thisMonthDiaries.some(
diary =>
diary.date ===
formatDateToNumber(
new Date(
selectedDate.getFullYear(),
selectedDate.getMonth(),
day,
),
),
) &&
styles.hasDiary,
]}>
Expand Down
15 changes: 13 additions & 2 deletions src/components/EmotionScore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ const EmotionScore = ({score}: Props) => {
<View style={styles.container}>
<View style={styles.scoreContainer}>
<Text style={styles.title}>오늘의 감정점수</Text>
<Text style={styles.score}>{formatPositiveNumber(score)}</Text>
<Text style={styles.score}>
{score >= -3 ? formatPositiveNumber(score) : '점수 시스템 에러!'}
</Text>
</View>
<View style={styles.barContainer}>
<View style={styles.barScoreContainer}>
Expand All @@ -29,7 +31,12 @@ const EmotionScore = ({score}: Props) => {
</View>
<View style={styles.barBody}>
<View
style={[styles.barIndicator, {width: 220 * scoreToPercent(score)}]}
style={[
styles.barIndicator,
score >= -3
? {width: 220 * scoreToPercent(score)}
: styles.barIndicatorError,
]}
/>
</View>
</View>
Expand Down Expand Up @@ -76,6 +83,10 @@ const styles = StyleSheet.create({
backgroundColor: '#04E762',
height: 5,
},
barIndicatorError: {
width: 220,
backgroundColor: '#FF0000',
},
});

export default EmotionScore;
104 changes: 82 additions & 22 deletions src/components/Graph.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,64 @@
import React from 'react';
import React, {useState, useEffect} from 'react';
import {LineChart} from 'react-native-chart-kit';
import {Dimensions} from 'react-native';
import {Dimensions, StyleSheet, Text, View} from 'react-native';
import {ScrollView} from '@gluestack-ui/themed';
import {Q} from '@nozbe/watermelondb';
import {useDatabase} from '@nozbe/watermelondb/hooks';
import Sentiment from 'model/Sentiment';
import {formatDateToNumber} from 'util/dateUtil';
import {useSelectedDate} from 'contexts/SelectedDateContext';

const generateRandomData = (days: number) => {
const labels = [];
const dataPoints = [];
const screenWidth = Dimensions.get('window').width;

for (let i = 1; i <= days; i++) {
labels.push(`1/${i}`);
dataPoints.push(Math.floor(Math.random() * 100));
}
const Graph = () => {
const [labels, setLabels] = useState<string[]>([]);
const [dataPoints, setDataPoints] = useState<number[]>([]);

return {labels, dataPoints};
};
const {
data: {selectedDate},
} = useSelectedDate();

const Graph = () => {
const screenWidth = Dimensions.get('window').width;
const {labels, dataPoints} = generateRandomData(30);
const database = useDatabase();

useEffect(() => {
const fetchData = async () => {
const dayMonthStart = new Date(
selectedDate.getFullYear(),
selectedDate.getMonth(),
1,
0,
0,
0,
);
const dayMonthEnd = new Date(
selectedDate.getFullYear(),
selectedDate.getMonth() + 1,
0,
0,
0,
0,
);
const fetchedSentiments = await database
.get<Sentiment>('sentiments')
.query(
Q.and(
Q.where('date', Q.gte(formatDateToNumber(dayMonthStart))),
Q.where('date', Q.lte(formatDateToNumber(dayMonthEnd))),
),
);
setLabels([]);
setDataPoints([]);
fetchedSentiments.map(sentiment => {
const sentimentDate = new Date(sentiment.date);
setLabels(prev => [
...prev,
`${sentimentDate.getMonth() + 1}/${sentimentDate.getDate()}`,
]);
setDataPoints(prev => [...prev, sentiment.score]);
});
};
fetchData();
}, [database, selectedDate]);

const data = {
labels: labels,
Expand All @@ -28,7 +69,7 @@ const Graph = () => {
strokeWidth: 2,
},
],
legend: ['Rainy Days'],
legend: ['감정 점수'],
};

const chartConfig = {
Expand All @@ -43,15 +84,34 @@ const Graph = () => {
};

return (
<ScrollView horizontal width={screenWidth}>
<LineChart
data={data}
height={220}
width={35 * 31}
chartConfig={chartConfig}
/>
<ScrollView horizontal width={screenWidth} minHeight={220}>
{dataPoints.length ? (
<LineChart
data={data}
height={220}
width={35 * 31}
chartConfig={chartConfig}
/>
) : (
<View style={style.textContainer}>
<Text style={style.noDataText}>아직 감정 데이터가 없어요!</Text>
</View>
)}
</ScrollView>
);
};

const style = StyleSheet.create({
textContainer: {
width: screenWidth,
justifyContent: 'center',
alignItems: 'center',
},
noDataText: {
alignSelf: 'center',
textAlign: 'center',
fontSize: 20,
},
});

export default Graph;
Loading

0 comments on commit 3d2bc0b

Please sign in to comment.