-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #143 from boostcampwm2023/132-대회-페이지-내의-웹소켓-연결-상태를…
…-확인할-수-있는-기능 [#132] 대회 페이지 내의 웹소켓 연결 상태를 확인할 수 있는 기능
- Loading branch information
Showing
8 changed files
with
211 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
interface Props { | ||
size: string; | ||
color: string; | ||
} | ||
|
||
export default function Loading({ size, color }: Props) { | ||
return ( | ||
<svg | ||
xmlns="http://www.w3.org/2000/svg" | ||
width={size} | ||
height={size} | ||
viewBox="0 0 100 100" | ||
preserveAspectRatio="xMidYMid" | ||
> | ||
<circle | ||
cx="50" | ||
cy="50" | ||
fill="none" | ||
stroke={color} | ||
stroke-width="10" | ||
r="35" | ||
stroke-dasharray="164.93361431346415 56.97787143782138" | ||
> | ||
<animateTransform | ||
attributeName="transform" | ||
type="rotate" | ||
repeatCount="indefinite" | ||
dur="1s" | ||
values="0 50 50;360 50 50" | ||
keyTimes="0;1" | ||
></animateTransform> | ||
</circle> | ||
</svg> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { css } from '@style/css'; | ||
|
||
import Loading from '@/components/Common/Loading'; | ||
|
||
interface Props { | ||
isConnected: boolean; | ||
} | ||
|
||
export default function Connecting(props: Props) { | ||
if (!props.isConnected) return null; | ||
|
||
return ( | ||
<div className={rowStyle}> | ||
<span>연결 중...</span> | ||
<Loading color="darkorange" size="24px" /> | ||
</div> | ||
); | ||
} | ||
const rowStyle = css({ | ||
display: 'flex', | ||
gap: '0.5rem', | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { css } from '@style/css'; | ||
|
||
import Loading from '@/components/Common/Loading'; | ||
import useTimer from '@/hooks/timer/useTimer'; | ||
import { formatMilliSecond } from '@/utils/date'; | ||
import type { Socket } from '@/utils/socket'; | ||
|
||
interface Props { | ||
socket: Socket; | ||
endsAt: Date; | ||
isConnected?: boolean; | ||
} | ||
|
||
export default function Timer(props: Props) { | ||
let { socket, endsAt, isConnected } = props; | ||
// api 연결이 X endsAt 대신 임시로 만들어놓은 것. | ||
endsAt = new Date('2023-11-29T13:10:10.000Z'); | ||
const { remainMiliSeconds } = useTimer({ socket, endsAt }); | ||
|
||
if (isConnected && remainMiliSeconds !== -1) { | ||
// 연결도 되어있고, 서버 시간도 도착해서 count down을 시작할 수 있을 때 | ||
return ( | ||
<section className={wrapperStyle}> | ||
<div> | ||
<span className={timeTextStyle}>{formatMilliSecond(remainMiliSeconds, 'hh:mm:ss')}</span> | ||
</div> | ||
</section> | ||
); | ||
} | ||
|
||
return ( | ||
<section className={wrapperStyle}> | ||
<div> | ||
<section className={loadingBoxStyle}> | ||
<span className={disconnectedStyle}>연결 중...</span> | ||
<Loading color="darkred" size="24px" /> | ||
</section> | ||
</div> | ||
</section> | ||
); | ||
} | ||
|
||
const wrapperStyle = css({ | ||
display: 'flex', | ||
alignItems: 'center', | ||
}); | ||
|
||
const disconnectedStyle = css({ | ||
color: 'darkred', | ||
}); | ||
|
||
const loadingBoxStyle = css({ | ||
display: 'flex', | ||
gap: '1rem', | ||
}); | ||
|
||
const timeTextStyle = css({ | ||
color: 'lightgray', | ||
fontWeight: 'bold', | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; | ||
|
||
import { Socket } from '@/utils/socket'; | ||
|
||
interface UseTimer { | ||
socket: Socket; | ||
endsAt: Date; | ||
onTimeoutHandler?: () => void; | ||
} | ||
|
||
export default function useTimer({ socket, endsAt, onTimeoutHandler }: UseTimer) { | ||
const timerIntervalId = useRef<NodeJS.Timeout | null>(null); | ||
const endTime = useMemo(() => endsAt.getTime(), [endsAt]); | ||
const [remainMiliSeconds, setRemainMiliSeconds] = useState<number>(-1); | ||
useEffect(() => { | ||
console.log('타이머 실행'); | ||
// 웹 소켓 대신 사용. | ||
mockWebSocket(); | ||
if (!socket.hasListeners('ping')) { | ||
socket.on('ping', handlePingMessage); | ||
} | ||
}, [socket]); | ||
|
||
const handlePingMessage = useCallback((time: Date | string) => { | ||
if (timerIntervalId.current) clearInterval(timerIntervalId.current); | ||
|
||
time = typeof time === 'string' ? new Date(time) : time; | ||
const remainMiliSec = endTime - time.getTime(); | ||
setRemainMiliSeconds(remainMiliSec); | ||
timerIntervalId.current = setInterval(() => { | ||
console.log('1초마다 실행'); | ||
setRemainMiliSeconds((prev) => prev - 1000); | ||
}, 1000); | ||
}, []); | ||
|
||
// 웹 소켓 대신 사용. | ||
// 웹 소켓 연결 후 삭제 예정 | ||
const mockWebSocket = useCallback(() => { | ||
const delayFactor = 2000; | ||
setInterval(() => { | ||
console.log('ping 5초( + 네트워크 지연) 마다 실행'); | ||
const serverTime = new Date(); | ||
handlePingMessage(serverTime); | ||
}, 5000 + Math.random() * delayFactor); | ||
}, []); | ||
|
||
useEffect(() => { | ||
// TODO time 0이면 대시보드로 이동하는 로직 | ||
// 해당 PR에서 해결할 문제는 아니라 PASS | ||
if (Math.floor(remainMiliSeconds / 1000) <= 0) { | ||
if (typeof onTimeoutHandler === 'function') onTimeoutHandler(); | ||
// 나가는 로직 | ||
} | ||
}, [remainMiliSeconds]); | ||
return { remainMiliSeconds }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters