From bb87317d9b1e7fc29b8c3c2c2dbd68c191e9e760 Mon Sep 17 00:00:00 2001 From: jeongbbn Date: Thu, 25 Nov 2021 17:55:53 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=20=E2=9C=A8=20:=20=20=EB=AC=B4=ED=95=9C=20?= =?UTF-8?q?=EC=8A=A4=ED=81=AC=EB=A1=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=B2=84=EC=A0=84=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back-end/api-server/database/query.ts | 14 +++- back-end/api-server/routes/profile.ts | 22 +++++++ front-end/src/App.tsx | 4 ++ .../src/components/InfiniteScroll/index.tsx | 66 +++++++++++++++++++ .../src/components/InfiniteScroll/style.scss | 5 ++ 5 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 front-end/src/components/InfiniteScroll/index.tsx create mode 100644 front-end/src/components/InfiniteScroll/style.scss diff --git a/back-end/api-server/database/query.ts b/back-end/api-server/database/query.ts index eb7ab3d..b4815fa 100644 --- a/back-end/api-server/database/query.ts +++ b/back-end/api-server/database/query.ts @@ -19,9 +19,17 @@ export const insertIntoTable = (table, into, values) => { return connectionQuery(queryLine); }; -export const innerJoinTable = async (column, tableA, tableB, on = null, condition = null) => { - let queryLine = `SELECT ${column} FROM ${tableA} INNER JOIN ${tableB} ON ${on} `; - queryLine += condition ? `WHERE ${condition}` : ``; +export const innerJoinTable = async ( + column, + tableA, + tableB, + on = null, + condition = null, + limit = null +) => { + let queryLine = `SELECT ${column} FROM ${tableA} INNER JOIN ${tableB} ON ${on}`; + queryLine += condition ? ` WHERE ${condition}` : ``; + queryLine += limit ? ` LIMIT ${limit}` : ``; return connectionQuery(queryLine); }; diff --git a/back-end/api-server/routes/profile.ts b/back-end/api-server/routes/profile.ts index 06076e7..8507957 100644 --- a/back-end/api-server/routes/profile.ts +++ b/back-end/api-server/routes/profile.ts @@ -32,6 +32,17 @@ ProfileRouter.post('/total', async (req, res, next) => { } }); +ProfileRouter.post('/recent', async (req, res, next) => { + try { + const { nickname, offset, limit } = req.body; + const [{ oauth_id }] = await getOauthId(nickname); + const recentList = await getRecentInDB_new(oauth_id, offset, limit); + res.status(200).json({ recentList }); + } catch (error) { + res.status(401).json({ error: '잘못된 인증입니다.' }); + } +}); + ProfileRouter.patch('/', async (req, res, next) => { try { const { nickname, id } = req.body; @@ -91,4 +102,15 @@ const getRecentInDB = (id) => { ); }; +const getRecentInDB_new = (id, offset, limit) => { + return innerJoinTable( + 'game_date, game_mode, ranking, play_time, attack_cnt, attacked_cnt', + 'PLAY', + 'GAME_INFO', + 'PLAY.game_id = GAME_INFO.game_id', + `oauth_id='${id}'`, + `${offset}, ${limit}` + ); +}; + export default ProfileRouter; diff --git a/front-end/src/App.tsx b/front-end/src/App.tsx index b09e236..ea690a4 100644 --- a/front-end/src/App.tsx +++ b/front-end/src/App.tsx @@ -17,6 +17,8 @@ import RankingPage from './pages/RankingPage'; import ErrorPage from './pages/ErrorPage'; import './App.scss'; +import Test1 from './components/InfiniteScroll'; + function App() { let { auth } = useAuth(); const dispatch = useAppDispatch(); @@ -55,6 +57,8 @@ function App() { } /> } /> } /> + + } /> diff --git a/front-end/src/components/InfiniteScroll/index.tsx b/front-end/src/components/InfiniteScroll/index.tsx new file mode 100644 index 0000000..a415546 --- /dev/null +++ b/front-end/src/components/InfiniteScroll/index.tsx @@ -0,0 +1,66 @@ +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import './style.scss'; + +export default function InfinityScroll() { + const MAX_ROWS = 5; + + const [pageNum, setPageNum] = useState(0); + const [loading, setLoading] = useState(false); + + const rootRef = useRef(null); + const observerRef = useRef(null); + + const [list, setList] = useState([]); + const [hasMore, setHasMore] = useState(false); + + useEffect(() => { + setLoading(true); + + fetch('/api/profile/recent', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ nickname: '뭐', limit: MAX_ROWS, offset: pageNum }), + }) + .then((res) => res.json()) + .then((data) => { + setList((prev: any) => { + return [...prev, ...data.recentList]; + }); + setHasMore(data.recentList.length > 0); + setLoading(false); + }) + .catch((error) => { + console.log('error:', error); + }); + }, [pageNum]); + + const targetRef = useCallback( + (node) => { + if (loading) return; + let options = { + root: rootRef.current, + rootMargin: '0px', + threshold: 0, + }; + + if (observerRef.current) observerRef.current.disconnect(); + observerRef.current = new IntersectionObserver((entries) => { + if (entries[0].isIntersecting && hasMore) { + setPageNum((prev) => prev + MAX_ROWS); + } + }, options); + if (node) observerRef.current.observe(node); + }, + [loading, hasMore] + ); + + return ( +
+ {list.map((m: any, i: number) => { + return
{m['game_date']}
; + })} +
+ <>{loading &&
로딩중
} +
+ ); +} diff --git a/front-end/src/components/InfiniteScroll/style.scss b/front-end/src/components/InfiniteScroll/style.scss new file mode 100644 index 0000000..85abe0a --- /dev/null +++ b/front-end/src/components/InfiniteScroll/style.scss @@ -0,0 +1,5 @@ +.ScrollContainer { + background-color: rosybrown; + height: 100px; + overflow-y: scroll; +} From cb1a1d16abfafb740a0a0a38b36ef4fabe2fd2bd Mon Sep 17 00:00:00 2001 From: jeongbbn Date: Thu, 25 Nov 2021 21:11:37 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=E2=9C=A8=20:=20=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EC=B5=9C=EA=B7=BC=20=EC=A0=84=EC=A0=81=EC=97=90=20?= =?UTF-8?q?=EB=AC=B4=ED=95=9C=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back-end/api-server/routes/profile.ts | 21 ++----- front-end/src/App.tsx | 4 -- .../src/components/InfiniteScroll/index.tsx | 55 ++++++++++++++----- .../src/components/InfiniteScroll/style.scss | 16 +++++- front-end/src/pages/ProfilePage/index.tsx | 41 +++++--------- front-end/src/pages/ProfilePage/style.scss | 14 ----- front-end/src/pages/RankingPage/index.tsx | 2 + 7 files changed, 76 insertions(+), 77 deletions(-) diff --git a/back-end/api-server/routes/profile.ts b/back-end/api-server/routes/profile.ts index 8507957..5b5dd1d 100644 --- a/back-end/api-server/routes/profile.ts +++ b/back-end/api-server/routes/profile.ts @@ -23,9 +23,9 @@ ProfileRouter.post('/total', async (req, res, next) => { try { const [{ oauth_id }] = await getOauthId(req.body.nickname); const totalList = await getTotalInDB(oauth_id); - const recentList = await getRecentInDB(oauth_id); const [total, win] = totalList; - res.status(200).json({ total, win, recentList }); + const data = { ...total[0], ...win[0] }; + res.status(200).json(data); } catch (error) { console.log(error); res.status(401).json({ error: '잘못된 인증입니다.' }); @@ -36,9 +36,10 @@ ProfileRouter.post('/recent', async (req, res, next) => { try { const { nickname, offset, limit } = req.body; const [{ oauth_id }] = await getOauthId(nickname); - const recentList = await getRecentInDB_new(oauth_id, offset, limit); - res.status(200).json({ recentList }); + const data = await getRecentInDB(oauth_id, offset, limit); + res.status(200).json(data); } catch (error) { + console.log(error); res.status(401).json({ error: '잘못된 인증입니다.' }); } }); @@ -92,17 +93,7 @@ const getTotalInDB = async (id) => { ]); }; -const getRecentInDB = (id) => { - return innerJoinTable( - 'game_date, game_mode, ranking, play_time, attack_cnt, attacked_cnt', - 'PLAY', - 'GAME_INFO', - 'PLAY.game_id = GAME_INFO.game_id', - `oauth_id='${id}'` - ); -}; - -const getRecentInDB_new = (id, offset, limit) => { +const getRecentInDB = (id, offset, limit) => { return innerJoinTable( 'game_date, game_mode, ranking, play_time, attack_cnt, attacked_cnt', 'PLAY', diff --git a/front-end/src/App.tsx b/front-end/src/App.tsx index ea690a4..b09e236 100644 --- a/front-end/src/App.tsx +++ b/front-end/src/App.tsx @@ -17,8 +17,6 @@ import RankingPage from './pages/RankingPage'; import ErrorPage from './pages/ErrorPage'; import './App.scss'; -import Test1 from './components/InfiniteScroll'; - function App() { let { auth } = useAuth(); const dispatch = useAppDispatch(); @@ -57,8 +55,6 @@ function App() { } /> } /> } /> - - } /> diff --git a/front-end/src/components/InfiniteScroll/index.tsx b/front-end/src/components/InfiniteScroll/index.tsx index a415546..869de17 100644 --- a/front-end/src/components/InfiniteScroll/index.tsx +++ b/front-end/src/components/InfiniteScroll/index.tsx @@ -1,9 +1,35 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import './style.scss'; -export default function InfinityScroll() { - const MAX_ROWS = 5; +const drawRecent = (list: Array) => { + if (list.length === 0) return; + return ( + <> + {list.map((value) => ( +
+
{value.game_date.slice(0, 10)}
+
{value.game_mode === 'normal' ? '일반전' : '1 vs 1'}
+
{value.ranking}
+
{value.play_time}
+
{value.attack_cnt}
+
{value.attacked_cnt}
+
+ ))} + + ); +}; +export default function InfiniteScroll({ + nickname, + MAX_ROWS, + fetchURL, + type, +}: { + nickname: string | undefined; + MAX_ROWS: number; + fetchURL: string; + type: string; +}) { const [pageNum, setPageNum] = useState(0); const [loading, setLoading] = useState(false); @@ -13,20 +39,22 @@ export default function InfinityScroll() { const [list, setList] = useState([]); const [hasMore, setHasMore] = useState(false); + useEffect(() => console.log(hasMore), [hasMore]); + useEffect(() => { setLoading(true); - - fetch('/api/profile/recent', { + console.log(pageNum); + fetch(fetchURL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ nickname: '뭐', limit: MAX_ROWS, offset: pageNum }), + body: JSON.stringify({ nickname, limit: MAX_ROWS, offset: pageNum }), }) .then((res) => res.json()) .then((data) => { setList((prev: any) => { - return [...prev, ...data.recentList]; + return [...prev, ...data]; }); - setHasMore(data.recentList.length > 0); + setHasMore(data.length > 0); setLoading(false); }) .catch((error) => { @@ -39,7 +67,7 @@ export default function InfinityScroll() { if (loading) return; let options = { root: rootRef.current, - rootMargin: '0px', + rootMargin: '50px', threshold: 0, }; @@ -55,12 +83,13 @@ export default function InfinityScroll() { ); return ( -
- {list.map((m: any, i: number) => { - return
{m['game_date']}
; - })} +
+ {type === 'profile' && drawRecent(list)}
- <>{loading &&
로딩중
} + <>{loading &&
로딩중
}
); } diff --git a/front-end/src/components/InfiniteScroll/style.scss b/front-end/src/components/InfiniteScroll/style.scss index 85abe0a..b639c88 100644 --- a/front-end/src/components/InfiniteScroll/style.scss +++ b/front-end/src/components/InfiniteScroll/style.scss @@ -1,5 +1,15 @@ -.ScrollContainer { - background-color: rosybrown; - height: 100px; +@import 'common/styles/base'; + +.recent__list--scroll { + height: 250px; overflow-y: scroll; + + .recent__list { + display: grid; + grid-template-columns: repeat(6, 1fr); + text-align: center; + font-size: 17px; + padding: 15px 40px; + box-sizing: border-box; + } } diff --git a/front-end/src/pages/ProfilePage/index.tsx b/front-end/src/pages/ProfilePage/index.tsx index a466670..3f93da1 100644 --- a/front-end/src/pages/ProfilePage/index.tsx +++ b/front-end/src/pages/ProfilePage/index.tsx @@ -7,6 +7,7 @@ import { useNavigate, useParams } from 'react-router-dom'; import { useAppDispatch } from '../../app/hooks'; import { updateNickname } from '../../features/user/userSlice'; import { useSocket } from '../../context/SocketContext'; +import InfiniteScroll from '../../components/InfiniteScroll'; export default function Profile() { const { nickname } = useParams(); @@ -18,12 +19,14 @@ export default function Profile() { const translations = [ ['total_game_cnt', '총 게임 수'], ['total_play_time', '총 플레이 시간'], - ['single_player_win', '1vs1 승리 횟수'], + ['single_player_win', '1 vs 1 승리 횟수'], ['multi_player_win', '일반전 승리 횟수'], ['total_attack_cnt', '총 공격 횟수'], ]; + const [recentList, setRecentList] = useState([]); const [statsticsState, setStatsticsState] = useState({}); + const [editMode, setEditMode] = useState(false); const [userState, setUserState] = useState({ id: authProfile.id, @@ -49,24 +52,6 @@ export default function Profile() { ); }; - const drawRecent = (recentList: Array) => { - if (recentList.length === 0) return; - return ( - <> - {recentList.map((value) => ( -
-
{value.game_date.slice(0, 10)}
-
{value.game_mode === 'normal' ? '일반전' : '1 vs 1'}
-
{value.ranking}
-
{value.play_time}
-
{value.attack_cnt}
-
{value.attacked_cnt}
-
- ))} - - ); - }; - const changeTextArea = (e: React.ChangeEvent) => { if (!e.target) return; setUserState({ ...userState, stateMessage: e.target.value }); @@ -98,8 +83,6 @@ export default function Profile() { }; useEffect(() => { - setUserState({ ...userState, nickname }); - fetch('/api/profile/stateMessage', { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -121,15 +104,13 @@ export default function Profile() { }) .then((res) => res.json()) .then((data) => { - setStatsticsState({ ...statsticsState, ...data.total[0], ...data.win[0] }); - setRecentList([...data.recentList]); + setStatsticsState({ ...statsticsState, ...data }); }) .catch((error) => { navigate('/error/unauthorize', { replace: true }); console.log('error:', error); }); - return () => {}; - }, [nickname]); + }, []); return ( @@ -164,7 +145,7 @@ export default function Profile() { )}
-
+
통계
@@ -179,8 +160,12 @@ export default function Profile() {
{value}
))}
- -
{drawRecent(recentList)}
+
diff --git a/front-end/src/pages/ProfilePage/style.scss b/front-end/src/pages/ProfilePage/style.scss index 8136253..ec163a7 100644 --- a/front-end/src/pages/ProfilePage/style.scss +++ b/front-end/src/pages/ProfilePage/style.scss @@ -124,20 +124,6 @@ margin: 20px 30px 0px; box-sizing: border-box; } - - .recent-list__scroll { - height: 250px; - overflow: auto; - - .recent-list { - display: grid; - grid-template-columns: repeat(6, 1fr); - text-align: center; - font-size: 17px; - padding: 15px 40px; - box-sizing: border-box; - } - } } } } diff --git a/front-end/src/pages/RankingPage/index.tsx b/front-end/src/pages/RankingPage/index.tsx index cca1be8..65f012a 100644 --- a/front-end/src/pages/RankingPage/index.tsx +++ b/front-end/src/pages/RankingPage/index.tsx @@ -96,6 +96,7 @@ function RankingPage() { rankApiTemplate.nickName = inputRef?.current?.value; syncKeyWithServer(rankApiTemplate, categoryButtonState, modeButtonState); const res = await fetchGetRank(rankApiTemplate); + console.log(res.data, 'hihi'); setPlayers(res.data); }; @@ -103,6 +104,7 @@ function RankingPage() { (async function effect() { syncKeyWithServer(rankApiTemplate, categoryButtonState, modeButtonState); const res = await fetchGetRank(rankApiTemplate); + console.log(res.data, 'byeye'); setPlayers(res.data); })(); }, [categoryButtonState, modeButtonState]); From 75865b8a8568e409f75642b9e34c28b8ffb76f8d Mon Sep 17 00:00:00 2001 From: jeongbbn Date: Thu, 25 Nov 2021 21:16:16 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=94=A8=20:=20=EB=B9=84=EB=B0=80?= =?UTF-8?q?=EC=8A=A4=EB=9F=AC=EC=9A=B4=20console=EC=9D=84=20=EC=A7=80?= =?UTF-8?q?=EC=9B=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back-end/api-server/routes/gameRecord.ts | 1 - front-end/src/components/InfiniteScroll/index.tsx | 3 --- front-end/src/pages/RankingPage/index.tsx | 2 -- 3 files changed, 6 deletions(-) diff --git a/back-end/api-server/routes/gameRecord.ts b/back-end/api-server/routes/gameRecord.ts index b2ffc8e..a9a7c16 100644 --- a/back-end/api-server/routes/gameRecord.ts +++ b/back-end/api-server/routes/gameRecord.ts @@ -5,7 +5,6 @@ const GameRecordRouter = express.Router(); GameRecordRouter.post('/', async (req, res, next) => { const { game, players } = req.body; - console.log('hello', req.body); const insertGameInfoResult = await insertGameInfo(game); const insertPlayerInfoResult = await insertPlayerInfo(game.game_id, players); if (insertGameInfoResult && insertPlayerInfoResult) { diff --git a/front-end/src/components/InfiniteScroll/index.tsx b/front-end/src/components/InfiniteScroll/index.tsx index 869de17..f824d8c 100644 --- a/front-end/src/components/InfiniteScroll/index.tsx +++ b/front-end/src/components/InfiniteScroll/index.tsx @@ -39,11 +39,8 @@ export default function InfiniteScroll({ const [list, setList] = useState([]); const [hasMore, setHasMore] = useState(false); - useEffect(() => console.log(hasMore), [hasMore]); - useEffect(() => { setLoading(true); - console.log(pageNum); fetch(fetchURL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, diff --git a/front-end/src/pages/RankingPage/index.tsx b/front-end/src/pages/RankingPage/index.tsx index 65f012a..cca1be8 100644 --- a/front-end/src/pages/RankingPage/index.tsx +++ b/front-end/src/pages/RankingPage/index.tsx @@ -96,7 +96,6 @@ function RankingPage() { rankApiTemplate.nickName = inputRef?.current?.value; syncKeyWithServer(rankApiTemplate, categoryButtonState, modeButtonState); const res = await fetchGetRank(rankApiTemplate); - console.log(res.data, 'hihi'); setPlayers(res.data); }; @@ -104,7 +103,6 @@ function RankingPage() { (async function effect() { syncKeyWithServer(rankApiTemplate, categoryButtonState, modeButtonState); const res = await fetchGetRank(rankApiTemplate); - console.log(res.data, 'byeye'); setPlayers(res.data); })(); }, [categoryButtonState, modeButtonState]); From 2c6a4e82c2ccff6fe298689d5935be4b3854d048 Mon Sep 17 00:00:00 2001 From: jeongbbn Date: Thu, 25 Nov 2021 21:41:14 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=20=F0=9F=90=9B=20:=20map=ED=95=A8=EC=88=98?= =?UTF-8?q?=EC=97=90=20key=EB=A5=BC=20=EC=B6=94=EA=B0=80=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- front-end/src/components/InfiniteScroll/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front-end/src/components/InfiniteScroll/index.tsx b/front-end/src/components/InfiniteScroll/index.tsx index f824d8c..ceec057 100644 --- a/front-end/src/components/InfiniteScroll/index.tsx +++ b/front-end/src/components/InfiniteScroll/index.tsx @@ -6,7 +6,7 @@ const drawRecent = (list: Array) => { return ( <> {list.map((value) => ( -
+
{value.game_date.slice(0, 10)}
{value.game_mode === 'normal' ? '일반전' : '1 vs 1'}
{value.ranking}