Loading backend @ 6527610a Compare 8f036918 to 6527610a Original line number Diff line number Diff line Subproject commit 8f0369186abbf7b3776f7e1610213dbaeb79581a Subproject commit 6527610a9cfd352c67a6c77cc2859b8bf24caf9e frontend/src/components/Noticeboard/NoticeboardCard.tsx +26 −3 Original line number Diff line number Diff line Loading @@ -43,11 +43,34 @@ export const NoticeboardCard: FC<NoticeboardCardProps> = ({ message }) => { className={css` display: flex; align-items: center; column-gap: 0.3rem; column-gap: 0.5rem; `} > {message.createdBy && ( <> <Icon icon='user' /> <span>{message.createdBy?.username}</span> <div className={css` display: flex; column-gap: 0.3rem; `} > {message.createdBy.firstName && message.createdBy.lastName && ( <> <span> {message.createdBy.firstName}{' '} {message.createdBy.lastName} </span> <span>-</span> </> )} <span>{message.createdBy.username}</span> </div> </> )} </div> <span> Expires {timeFormat === 'relative' ? 'in' : 'at'}:{' '} Loading frontend/src/components/Status/TimeLeft.tsx +22 −7 Original line number Diff line number Diff line import { css } from '@emotion/css' import { GetExerciseTimeLeft, useTypedQuery } from '@inject/graphql' import { useSecondsFormatter } from '@inject/shared' import { memo, useEffect, useRef } from 'react' const wrapper = css` min-width: 8ch; min-width: 4ch; font-family: Arial, monospace; user-select: none; display: flex; justify-content: center; ` const DAY_IN_SECONDS = 60 * 60 * 24 const timeToTimer = (res: number) => new Date(res * 1000).toISOString().substring(11, 19) const timeToTimer = ( res: number, formatSeconds: (seconds: number) => string ) => { if (res > DAY_IN_SECONDS) { return formatSeconds(res) } return new Date(res * 1000).toISOString().substring(11, 19) } const TimeLeft = ({ teamId }: { teamId: string }) => { const timeLeftRef = useRef<HTMLSpanElement>(null) const timeLeftRef = useRef<HTMLSpanElement | null>(null) const timeLeft = useRef(0) const formatSeconds = useSecondsFormatter({ minimal: true, prefix: '>' }) useEffect(() => { const interval = setInterval(() => { timeLeft.current = timeLeft.current > 0 ? timeLeft.current - 1 : timeLeft.current if (timeLeftRef.current !== null) timeLeftRef.current.innerText = timeToTimer(timeLeft.current) timeLeftRef.current.innerText = timeToTimer( timeLeft.current, formatSeconds ) }, 1000) return () => { clearInterval(interval) } }, [timeLeftRef]) }, [formatSeconds, timeLeftRef]) const [{ data, fetching: loading, error }, refetch] = useTypedQuery({ query: GetExerciseTimeLeft, Loading Loading @@ -57,7 +72,7 @@ const TimeLeft = ({ teamId }: { teamId: string }) => { return ( <span className={wrapper} ref={timeLeftRef}> {timeToTimer(data.exerciseTimeLeft)} {timeToTimer(data.exerciseTimeLeft, formatSeconds)} </span> ) } Loading Loading
backend @ 6527610a Compare 8f036918 to 6527610a Original line number Diff line number Diff line Subproject commit 8f0369186abbf7b3776f7e1610213dbaeb79581a Subproject commit 6527610a9cfd352c67a6c77cc2859b8bf24caf9e
frontend/src/components/Noticeboard/NoticeboardCard.tsx +26 −3 Original line number Diff line number Diff line Loading @@ -43,11 +43,34 @@ export const NoticeboardCard: FC<NoticeboardCardProps> = ({ message }) => { className={css` display: flex; align-items: center; column-gap: 0.3rem; column-gap: 0.5rem; `} > {message.createdBy && ( <> <Icon icon='user' /> <span>{message.createdBy?.username}</span> <div className={css` display: flex; column-gap: 0.3rem; `} > {message.createdBy.firstName && message.createdBy.lastName && ( <> <span> {message.createdBy.firstName}{' '} {message.createdBy.lastName} </span> <span>-</span> </> )} <span>{message.createdBy.username}</span> </div> </> )} </div> <span> Expires {timeFormat === 'relative' ? 'in' : 'at'}:{' '} Loading
frontend/src/components/Status/TimeLeft.tsx +22 −7 Original line number Diff line number Diff line import { css } from '@emotion/css' import { GetExerciseTimeLeft, useTypedQuery } from '@inject/graphql' import { useSecondsFormatter } from '@inject/shared' import { memo, useEffect, useRef } from 'react' const wrapper = css` min-width: 8ch; min-width: 4ch; font-family: Arial, monospace; user-select: none; display: flex; justify-content: center; ` const DAY_IN_SECONDS = 60 * 60 * 24 const timeToTimer = (res: number) => new Date(res * 1000).toISOString().substring(11, 19) const timeToTimer = ( res: number, formatSeconds: (seconds: number) => string ) => { if (res > DAY_IN_SECONDS) { return formatSeconds(res) } return new Date(res * 1000).toISOString().substring(11, 19) } const TimeLeft = ({ teamId }: { teamId: string }) => { const timeLeftRef = useRef<HTMLSpanElement>(null) const timeLeftRef = useRef<HTMLSpanElement | null>(null) const timeLeft = useRef(0) const formatSeconds = useSecondsFormatter({ minimal: true, prefix: '>' }) useEffect(() => { const interval = setInterval(() => { timeLeft.current = timeLeft.current > 0 ? timeLeft.current - 1 : timeLeft.current if (timeLeftRef.current !== null) timeLeftRef.current.innerText = timeToTimer(timeLeft.current) timeLeftRef.current.innerText = timeToTimer( timeLeft.current, formatSeconds ) }, 1000) return () => { clearInterval(interval) } }, [timeLeftRef]) }, [formatSeconds, timeLeftRef]) const [{ data, fetching: loading, error }, refetch] = useTypedQuery({ query: GetExerciseTimeLeft, Loading Loading @@ -57,7 +72,7 @@ const TimeLeft = ({ teamId }: { teamId: string }) => { return ( <span className={wrapper} ref={timeLeftRef}> {timeToTimer(data.exerciseTimeLeft)} {timeToTimer(data.exerciseTimeLeft, formatSeconds)} </span> ) } Loading