-
Notifications
You must be signed in to change notification settings - Fork 2
[FE] SISC1-164 [FEAT] : 베팅 페이지 API 연동 #108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4fdd0f4
60288ea
61b212d
e113a7d
016a4f2
29c4468
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,32 +1,51 @@ | ||||||||||||||||
| import styles from './BettingHistory.module.css'; | ||||||||||||||||
| import icon1 from '../../assets/at_icon_1.png'; | ||||||||||||||||
| // import icon1 from '../../assets/at_icon_1.png'; | ||||||||||||||||
| import StockInfoItem from './StockInfoItem'; | ||||||||||||||||
| import { dailyBettingHistory } from '../../utils/dailyBettingHistory'; | ||||||||||||||||
| import { weeklyBettingHistory } from '../../utils/weeklyBettingHistory'; | ||||||||||||||||
| import Pagination from './Pagination'; | ||||||||||||||||
| import { useState, useEffect } from 'react'; | ||||||||||||||||
| import { | ||||||||||||||||
| getDailyBetHistory, | ||||||||||||||||
| getWeeklyBetHistory, | ||||||||||||||||
| } from '../../utils/bettingHistory'; | ||||||||||||||||
|
|
||||||||||||||||
| const BettingHistory = ({ type }) => { | ||||||||||||||||
| const formatDate = (dateStr) => { | ||||||||||||||||
| const [year, month, day] = dateStr.split('-'); | ||||||||||||||||
| return `${year}년 ${month}월 ${day}일`; | ||||||||||||||||
| }; | ||||||||||||||||
|
|
||||||||||||||||
| const [data, setData] = useState([]); | ||||||||||||||||
| const [currentPage, setCurrentPage] = useState(1); | ||||||||||||||||
| const [loading, setLoading] = useState(false); | ||||||||||||||||
| const [error, setError] = useState(null); | ||||||||||||||||
| const itemsPerPage = 5; | ||||||||||||||||
|
|
||||||||||||||||
| useEffect(() => { | ||||||||||||||||
| async function fetchData() { | ||||||||||||||||
| setLoading(true); | ||||||||||||||||
| setError(null); | ||||||||||||||||
| try { | ||||||||||||||||
| if (type === 'daily') { | ||||||||||||||||
| const res = await getDailyBetHistory(); | ||||||||||||||||
| setData(res); | ||||||||||||||||
| } else { | ||||||||||||||||
| const res = await getWeeklyBetHistory(); | ||||||||||||||||
| setData(res); | ||||||||||||||||
| } | ||||||||||||||||
| } catch (err) { | ||||||||||||||||
| setError(err.message || '데이터를 불러오는데 실패했습니다.'); | ||||||||||||||||
| setData([]); | ||||||||||||||||
| } finally { | ||||||||||||||||
| setLoading(false); | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
| fetchData(); | ||||||||||||||||
| }, [type]); | ||||||||||||||||
|
Comment on lines
+18
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 비동기 작업 정리 메커니즘이 누락되었습니다. 컴포넌트가 언마운트되는 동안 비동기 작업이 진행 중인 경우, 언마운트된 컴포넌트에서 상태 업데이트가 발생하여 메모리 누수 및 React 경고가 발생할 수 있습니다. 다음과 같이 cleanup 함수를 추가하세요: useEffect(() => {
+ let isMounted = true;
async function fetchData() {
setLoading(true);
setError(null);
try {
if (type === 'daily') {
const res = await getDailyBetHistory();
- setData(res);
+ if (isMounted) setData(res);
} else {
const res = await getWeeklyBetHistory();
- setData(res);
+ if (isMounted) setData(res);
}
} catch (err) {
- setError(err.message || '데이터를 불러오는데 실패했습니다.');
- setData([]);
+ if (isMounted) {
+ setError(err.message || '데이터를 불러오는데 실패했습니다.');
+ setData([]);
+ }
} finally {
- setLoading(false);
+ if (isMounted) setLoading(false);
}
}
fetchData();
+ return () => {
+ isMounted = false;
+ };
}, [type]);🤖 Prompt for AI Agents |
||||||||||||||||
|
|
||||||||||||||||
| // 주간/일간 바뀔 때 페이지 초기화 | ||||||||||||||||
| useEffect(() => { | ||||||||||||||||
| setCurrentPage(1); | ||||||||||||||||
| }, [type]); | ||||||||||||||||
|
|
||||||||||||||||
| const mockBetHistory = | ||||||||||||||||
| type === 'weekly' ? weeklyBettingHistory : dailyBettingHistory; | ||||||||||||||||
|
|
||||||||||||||||
| const totalPages = Math.ceil(mockBetHistory.length / itemsPerPage); | ||||||||||||||||
| const totalPages = Math.ceil(data.length / itemsPerPage); | ||||||||||||||||
|
|
||||||||||||||||
| // 현재 페이지에 해당하는 데이터만 slice | ||||||||||||||||
| const currentData = mockBetHistory.slice( | ||||||||||||||||
| const currentData = data.slice( | ||||||||||||||||
| (currentPage - 1) * itemsPerPage, | ||||||||||||||||
| currentPage * itemsPerPage | ||||||||||||||||
| ); | ||||||||||||||||
|
|
@@ -35,43 +54,55 @@ const BettingHistory = ({ type }) => { | |||||||||||||||
| setCurrentPage(page); | ||||||||||||||||
| }; | ||||||||||||||||
|
|
||||||||||||||||
| const getPercentChange = (prev, next) => { | ||||||||||||||||
| return (((next - prev) / prev) * 100).toFixed(2); | ||||||||||||||||
| }; | ||||||||||||||||
|
Comment on lines
+57
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 0으로 나누기 오류 가능성이 있습니다.
다음과 같이 가드를 추가하세요: const getPercentChange = (prev, next) => {
+ if (!prev || prev === 0) return '0.00';
return (((next - prev) / prev) * 100).toFixed(2);
};📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||
|
|
||||||||||||||||
| if (loading) return <div>Loading...</div>; | ||||||||||||||||
| else if (error) return <div>에러: {error}</div>; | ||||||||||||||||
| else if (data.length === 0) { | ||||||||||||||||
| return <div>베팅 내역이 없습니다.</div>; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| return ( | ||||||||||||||||
| <> | ||||||||||||||||
| {currentData.map((history, index) => ( | ||||||||||||||||
| {currentData.map((item, index) => ( | ||||||||||||||||
| <div | ||||||||||||||||
| key={index} | ||||||||||||||||
| className={`${styles['daily-betting-card']} ${history.isCorrect ? styles['correct-card'] : styles['incorrect-card']}`} | ||||||||||||||||
| className={`${styles['daily-betting-card']} ${item.collect ? styles['correct-card'] : styles['incorrect-card']}`} | ||||||||||||||||
| > | ||||||||||||||||
| <button | ||||||||||||||||
| className={`${styles['result-icon']} ${history.isCorrect ? styles.correct : styles.incorrect}`} | ||||||||||||||||
| className={`${styles['result-icon']} ${item.collect ? styles.correct : styles.incorrect}`} | ||||||||||||||||
| > | ||||||||||||||||
| {history.isCorrect ? 'v' : 'x'} | ||||||||||||||||
| {item.collect ? 'v' : 'x'} | ||||||||||||||||
| </button> | ||||||||||||||||
| <span className={styles['date']}> | ||||||||||||||||
| {formatDate(history.date)} 베팅 | ||||||||||||||||
| </span> | ||||||||||||||||
| <span className={styles['date']}>{item.round.title}</span> | ||||||||||||||||
| <div className={styles['stock-info']}> | ||||||||||||||||
| <StockInfoItem label="종목" value={history.symbol} /> | ||||||||||||||||
| <StockInfoItem label="종목" value={item.round.symbol} /> | ||||||||||||||||
| <StockInfoItem | ||||||||||||||||
| label="다음 날 종가" | ||||||||||||||||
| value={history.nextClosePrice} | ||||||||||||||||
| value={item.round.settleClosePrice} | ||||||||||||||||
| /> | ||||||||||||||||
| <StockInfoItem label="종가" value={history.closePrice} /> | ||||||||||||||||
| <StockInfoItem label="종가" value={item.round.previousClosePrice} /> | ||||||||||||||||
| <div className={styles['stock-change']}> | ||||||||||||||||
| <span className={styles['change-value']}>{'->'}</span> | ||||||||||||||||
| <span className={styles['change-value']}> | ||||||||||||||||
| {history.changePercent}% | ||||||||||||||||
| {getPercentChange( | ||||||||||||||||
| item.round.previousClosePrice, | ||||||||||||||||
| item.round.settleClosePrice | ||||||||||||||||
| )} | ||||||||||||||||
| % | ||||||||||||||||
| </span> | ||||||||||||||||
| </div> | ||||||||||||||||
| {/* 베팅 결과 */} | ||||||||||||||||
| <div className={styles['bet-result']}> | ||||||||||||||||
| <div className={styles['bet-point']}> | ||||||||||||||||
| {/* <div className={styles['bet-point']}> | ||||||||||||||||
| <img src={icon1} className={styles['icon']} />+ | ||||||||||||||||
| <span>{history.points}P</span> | ||||||||||||||||
| <span>{item.points}P</span> | ||||||||||||||||
| </div> | ||||||||||||||||
| <div className={styles['divider']} /> | ||||||||||||||||
| <span>{history.participants}명</span> | ||||||||||||||||
| {history.result === 'UP' ? ( | ||||||||||||||||
| <span>{item.participants}명</span> */} | ||||||||||||||||
| {item.round.resultOption === 'RISE' ? ( | ||||||||||||||||
| <button className={styles['up-button']}>상승 ↑</button> | ||||||||||||||||
| ) : ( | ||||||||||||||||
| <button className={styles['down-button']}>하락 ↓</button> | ||||||||||||||||
|
|
||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| import { api } from '../utils/axios.js'; | ||
|
|
||
| const betHistory = async () => { | ||
| try { | ||
| const res = await api.get('/api/user-bets/history'); | ||
| return res.data; | ||
| } catch (error) { | ||
| console.log(error.message); | ||
| return null; | ||
| } | ||
| }; | ||
|
|
||
| export const getDailyBetHistory = async () => { | ||
| const data = await betHistory(); | ||
| if (!data) return []; | ||
| return data.filter((item) => item.round.scope === 'DAILY'); | ||
| }; | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| export const getWeeklyBetHistory = async () => { | ||
| const data = await betHistory(); | ||
| if (!data) return []; | ||
| return data.filter((item) => item.round.scope === 'WEEKLY'); | ||
| }; | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,21 @@ | ||
| export const mockDailyBet = { | ||
| date: '2025-08-25', | ||
| symbol: 'AAPL', | ||
| closePrice: 96.3, | ||
| upperBet: 300, | ||
| lowerBet: 300, | ||
| upBetCount: 200, | ||
| downBetCount: 200, | ||
| import { api } from '../utils/axios.js'; | ||
|
|
||
| export const dailyBet = async () => { | ||
| try { | ||
| const res = await api.get('/api/bet-rounds/DAILY'); | ||
| return res.data; | ||
| } catch (error) { | ||
| console.log(error.message); | ||
| return null; | ||
| } | ||
| }; | ||
|
|
||
| export const mockWeeklyBet = { | ||
| date: '2025-08-18', | ||
| symbol: 'AAPL', | ||
| closePrice: 98.5, | ||
| upperBet: 350, | ||
| lowerBet: 300, | ||
| upBetCount: 150, | ||
| downBetCount: 230, | ||
| export const weeklyBet = async () => { | ||
| try { | ||
| const res = await api.get('/api/bet-rounds/WEEKLY'); | ||
| return res.data; | ||
| } catch (error) { | ||
| console.log(error.message); | ||
| return null; | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
주석 처리된 코드 제거 필요
주석 처리된 코드는 버전 관리 시스템에서 이력을 확인할 수 있으므로, 코드베이스를 깔끔하게 유지하기 위해 제거하는 것이 좋습니다.
다음 주석 처리된 코드를 제거하세요:
// import icon1 from '../../assets/at_icon_1.png';Also applies to: 9-10, 61-66, 77-82
🤖 Prompt for AI Agents