-
[Spring Boot/React] Google Charts API 연동 - 주간 소비 리포트 만들기Project/외국인 관광객을 위한 카드 플랫폼 2024. 8. 9. 10:52
- 주간 소비 리포트 만들기(백연동o / ui 는아직x) - 구글 차트 api 사용
- 결제 내역 데이터 가져오기
- 총 결제 금액 계산
- 월 및 주 선택에 따른 데이터 필터링
- 총 지출, 입금, 출금 내역 필터링
- 차트와 필터링된 데이터를 UI에 표시
1. 컴포넌트 상태 및 데이터 가져오기
const WeeklyChart = () => { const [usage, setUsage] = useState([]); const [totalPrice, setTotalPrice] = useState(0); const [data, setData] = useState(initialData); // 초기 데이터 설정 const [selectedMonth, setSelectedMonth] = useState(() => { const today = new Date(); return `${today.getFullYear()}-${(today.getMonth() + 1).toString().padStart(2, '0')}`; }); const [selectedWeek, setSelectedWeek] = useState("1"); const [filteredUsage, setFilteredUsage] = useState([]); // 필터링된 데이터를 저장할 상태 추가 const [filter, setFilter] = useState("total"); // 추가된 필터 상태 useEffect(() => { axios.get('/api/payment/list') .then(response => { console.log(response.data); setUsage(response.data); // 총금액 계산 const total = response.data.reduce((acc, curr) => acc + curr.paymentPrice, 0); setTotalPrice(total); }) .catch(error => { console.log('에러에러', error); }); }, []);
- useState를 사용하여 상태를 설정합니다.
- useEffect를 사용하여 컴포넌트가 처음 마운트될 때 서버에서 데이터를 가져옵니다.
2. 선택된 월과 주에 따른 데이터 필터링
useEffect(() => { // 선택한 월과 주의 데이터 필터링 const filteredData = usage.filter(item => { const date = new Date(item.paymentDate); const month = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}`; const week = getWeekOfMonth(date); return month === selectedMonth && week.toString() === selectedWeek; }); // 요일별 소비 금액 집계 const dayTotals = filteredData.reduce((acc, curr) => { const date = new Date(curr.paymentDate); const day = date.getDay(); // 0 (일요일)부터 6 (토요일)까지 반환 acc[day] = (acc[day] || 0) + curr.paymentPrice; return acc; }, {}); // 초기 데이터 복사 및 업데이트 const newData = initialData.map((item, index) => { if (index === 0) return item; return [item[0], 0, item[2], "0원"]; }); let cumulativeTotal = 0; Object.keys(dayTotals).forEach(day => { cumulativeTotal += dayTotals[day]; newData[parseInt(day) + 1][1] = cumulativeTotal; newData[parseInt(day) + 1][3] = `${cumulativeTotal}원`; }); // 가장 높은 값을 찾아 색상 변경 const maxIndex = newData.reduce((maxIdx, row, idx, arr) => row[1] > arr[maxIdx][1] ? idx : maxIdx, 1); newData[maxIndex][2] = "#476EFF"; setData(newData); setFilteredUsage(filteredData); // 필터링된 데이터를 설정 }, [selectedMonth, selectedWeek, usage]);
- selectedMonth와 selectedWeek가 변경될 때마다 데이터를 필터링하여 filteredUsage 상태에 저장합니다.
- 요일별 소비 금액을 계산하고 차트 데이터를 업데이트합니다.
3. 월과 주 옵션 생성
// 2024년 1월부터 현재 월까지의 옵션 생성 const generateMonthOptions = () => { const options = []; const currentDate = new Date(); const currentYear = currentDate.getFullYear(); if (currentYear !== 2024) return options; const currentMonth = currentDate.getMonth() + 1; for (let month = currentMonth; month >= 1; month--) { const value = `2024-${month.toString().padStart(2, '0')}`; options.push(<option key={value} value={value}>2024년 {month}월</option>); } return options; }; // 첫째주부터 다섯째주까지의 옵션 생성 const generateWeekOptions = () => { const weekNames = ["첫째주", "둘째주", "셋째주", "넷째주", "다섯째주"]; return weekNames.map((name, index) => ( <option key={index + 1} value={index + 1}>{name}</option> )); };
- generateMonthOptions: 월 옵션을 생성합니다.
- generateWeekOptions: 주 옵션을 생성합니다.
4. 필터링된 데이터 반환
const getFilteredUsageByFilter = () => { if (filter === "income") { return filteredUsage.filter(item => item.paymentPrice > 0); } else if (filter === "expense") { return filteredUsage.filter(item => item.paymentPrice < 0); } else { return filteredUsage; // 총 지출 (모든 데이터) } };
getFilteredUsageByFilter: filter 상태에 따라 데이터를 필터링하여 반환합니다.
- 전체 코드
import React, { useEffect, useState } from 'react'; import { Chart } from "react-google-charts"; import '../../assets/WeeklyChart.css'; import axios from 'axios'; const initialData = [ ["요일", "소비 금액", { role: "style" }, { role: "annotation" }], ["Sat", 0, "#EDF0F7", "0원"], ["Sun", 0, "#EDF0F7", "0원"], ["Mon", 0, "#EDF0F7", "0원"], ["Tue", 0, "#EDF0F7", "0원"], ["Wed", 0, "#EDF0F7", "0원"], ["Thu", 0, "#EDF0F7", "0원"], ["Fri", 0, "#EDF0F7", "0원"] ]; const options = { title: "주간 소비 리포트", hAxis: { gridlines: { color: 'transparent' }, baselineColor: 'transparent' }, vAxis: { gridlines: { color: 'transparent' }, baselineColor: 'transparent', textPosition: 'none' }, legend: "none", bar: { groupWidth: "80%" }, isStacked: true, animation: { startup: true, easing: 'inAndOut', duration: 1000, }, chartArea: { width: '90%', height: '70%' }, annotations: { alwaysOutside: true, textStyle: { fontSize: 14, auraColor: 'none', color: '#000' }, stem: { color: 'transparent' } } }; const getWeekOfMonth = (date) => { const firstDay = new Date(date.getFullYear(), date.getMonth(), 1).getDay(); return Math.ceil((date.getDate() + firstDay) / 7); }; const WeeklyChart = () => { const [usage, setUsage] = useState([]); const [totalPrice, setTotalPrice] = useState(0); const [data, setData] = useState(initialData); // 초기 데이터 설정 const [selectedMonth, setSelectedMonth] = useState(() => { const today = new Date(); return `${today.getFullYear()}-${(today.getMonth() + 1).toString().padStart(2, '0')}`; }); const [selectedWeek, setSelectedWeek] = useState("1"); const [filteredUsage, setFilteredUsage] = useState([]); // 필터링된 데이터를 저장할 상태 추가 const [filter, setFilter] = useState("total"); // 추가된 필터 상태 useEffect(() => { axios.get('/api/payment/list') .then(response => { console.log(response.data); setUsage(response.data); // 총금액 계산 const total = response.data.reduce((acc, curr) => acc + curr.paymentPrice, 0); setTotalPrice(total); }) .catch(error => { console.log('에러에러', error); }); }, []); useEffect(() => { // 선택한 월과 주의 데이터 필터링 const filteredData = usage.filter(item => { const date = new Date(item.paymentDate); const month = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}`; const week = getWeekOfMonth(date); return month === selectedMonth && week.toString() === selectedWeek; }); // 요일별 소비 금액 집계 const dayTotals = filteredData.reduce((acc, curr) => { const date = new Date(curr.paymentDate); const day = date.getDay(); // 0 (일요일)부터 6 (토요일)까지 반환 acc[day] = (acc[day] || 0) + curr.paymentPrice; return acc; }, {}); // 초기 데이터 복사 및 업데이트 const newData = initialData.map((item, index) => { if (index === 0) return item; return [item[0], 0, item[2], "0원"]; }); let cumulativeTotal = 0; Object.keys(dayTotals).forEach(day => { cumulativeTotal += dayTotals[day]; newData[parseInt(day) + 1][1] = cumulativeTotal; newData[parseInt(day) + 1][3] = `${cumulativeTotal}원`; }); // 가장 높은 값을 찾아 색상 변경 const maxIndex = newData.reduce((maxIdx, row, idx, arr) => row[1] > arr[maxIdx][1] ? idx : maxIdx, 1); newData[maxIndex][2] = "#476EFF"; setData(newData); setFilteredUsage(filteredData); // 필터링된 데이터를 설정 }, [selectedMonth, selectedWeek, usage]); // 2024년 1월부터 현재 월까지의 옵션 생성 const generateMonthOptions = () => { const options = []; const currentDate = new Date(); const currentYear = currentDate.getFullYear(); if (currentYear !== 2024) return options; const currentMonth = currentDate.getMonth() + 1; for (let month = currentMonth; month >= 1; month--) { const value = `2024-${month.toString().padStart(2, '0')}`; options.push(<option key={value} value={value}>2024년 {month}월</option>); } return options; }; // 첫째주부터 다섯째주까지의 옵션 생성 const generateWeekOptions = () => { const weekNames = ["첫째주", "둘째주", "셋째주", "넷째주", "다섯째주"]; return weekNames.map((name, index) => ( <option key={index + 1} value={index + 1}>{name}</option> )); }; // 필터링된 데이터 반환 const getFilteredUsageByFilter = () => { if (filter === "income") { return filteredUsage.filter(item => item.paymentPrice > 0); } else if (filter === "expense") { return filteredUsage.filter(item => item.paymentPrice < 0); } else { return filteredUsage; // 총 지출 (모든 데이터) } }; return ( <div className="chart-container"> <div> <label>월 선택: </label> <select value={selectedMonth} onChange={(e) => setSelectedMonth(e.target.value)}> {generateMonthOptions()} </select> <label>주 선택: </label> <select value={selectedWeek} onChange={(e) => setSelectedWeek(e.target.value)}> {generateWeekOptions()} </select> </div> <h2>{selectedMonth.replace('-', '년 ')} {generateWeekOptions().find(option => option.props.value.toString() === selectedWeek).props.children} 주간 소비 리포트</h2> {/* 선택한 년도, 월 및 주 표시 */} <Chart chartType="ColumnChart" width="460px" height="460px" data={data} options={options} loader={<div>Loading Chart...</div>} /> <div>주간 총 소비 금액: {totalPrice.toLocaleString()}원</div> {/* 필터 버튼 */} <div> <button onClick={() => setFilter("total")}>총 지출 내역</button> <button onClick={() => setFilter("income")}>입금 내역</button> <button onClick={() => setFilter("expense")}>출금 내역</button> </div> {/* 결제내역 */} { getFilteredUsageByFilter().map((usage, index) => { return ( <div key={index}> <div>가맹점이름: {usage.storeName}</div> <div>결제금액 : {usage.paymentPrice}</div> <div>결제날짜 : {new Date(usage.paymentDate).toLocaleString()}</div> <p></p> <br/> </div> ); }) } </div> ); }; export default WeeklyChart;
- 사용자가 선택한 월과 주에 따라 데이터를 필터링하여 차트와 함께 표시합니다.
- 총 지출, 입금 내역, 출금 내역 버튼을 클릭하여 필터링된 데이터를 화면에 렌더링합니다.
- 결과화면
'Project > 외국인 관광객을 위한 카드 플랫폼' 카테고리의 다른 글
[Spring Boot/React] 카드 신청 페이지 제작 (0) 2024.08.10 [Spring Boot/React] 소비 패턴 그래프 생성 시 백과 연동 문제 해결 (0) 2024.08.09 [Spring Boot/React] 카드 사용 내역 페이지 만들기 (0) 2024.08.08 [Spring Boot/React] 카드 CRUD 연동해 카드 슬라이드 UI 제작 (0) 2024.08.07 [React] Google Charts API 연동 / 소비 패턴 분석, 주간 소비 리포트 만들기 (0) 2024.08.06