Loading frontend/src/actionlog/InjectMessage/Content/EmailContent.tsx +9 −0 Original line number Original line Diff line number Diff line import ContentComponent from '@/components/ContentComponent' import ContentComponent from '@/components/ContentComponent' import { Button } from '@blueprintjs/core' import { css } from '@emotion/css' import { css } from '@emotion/css' import type { EmailDetails } from '@inject/graphql/fragment-types' import type { EmailDetails } from '@inject/graphql/fragment-types' import type { FC } from 'react' import type { FC } from 'react' import { alignRight } from './classes' const wrapper = css` const wrapper = css` display: flex; display: flex; Loading @@ -14,6 +16,7 @@ interface EmailContentProps { teamId: string teamId: string exerciseId: string exerciseId: string inInstructor: boolean inInstructor: boolean onClose?: () => void } } const EmailContent: FC<EmailContentProps> = ({ const EmailContent: FC<EmailContentProps> = ({ Loading @@ -21,6 +24,7 @@ const EmailContent: FC<EmailContentProps> = ({ teamId, teamId, exerciseId, exerciseId, inInstructor, inInstructor, onClose, }) => ( }) => ( <div className={wrapper}> <div className={wrapper}> <ContentComponent <ContentComponent Loading @@ -29,6 +33,11 @@ const EmailContent: FC<EmailContentProps> = ({ exerciseId={exerciseId} exerciseId={exerciseId} inInstructor={inInstructor} inInstructor={inInstructor} /> /> {onClose && ( <div className={alignRight}> <Button intent='primary' text='Close' onClick={onClose} /> </div> )} </div> </div> ) ) Loading frontend/src/actionlog/InjectMessage/Content/InjectContent.tsx +8 −1 Original line number Original line Diff line number Diff line Loading @@ -13,6 +13,7 @@ import useBlockableMutation from '@inject/graphql/utils/useBlockableMutation' import { timedFormatter } from '@inject/shared/components/StyledTag/Timestamp' import { timedFormatter } from '@inject/shared/components/StyledTag/Timestamp' import type { FC } from 'react' import type { FC } from 'react' import { useMemo } from 'react' import { useMemo } from 'react' import { alignRight } from './classes' const wrapper = css` const wrapper = css` display: flex; display: flex; Loading Loading @@ -82,7 +83,7 @@ const InjectContent: FC<InjectContentProps> = ({ exerciseId={exerciseId} exerciseId={exerciseId} inInstructor={inInstructor} inInstructor={inInstructor} /> /> {confirmation && ( {confirmation ? ( <Done done={!!confirmed} title={title}> <Done done={!!confirmed} title={title}> <Button <Button intent='primary' intent='primary' Loading @@ -93,6 +94,12 @@ const InjectContent: FC<InjectContentProps> = ({ title={title} title={title} /> /> </Done> </Done> ) : ( onClose && ( <div className={alignRight}> <Button intent='primary' text='Close' onClick={onClose} /> </div> ) )} )} </div> </div> ) ) Loading frontend/src/actionlog/InjectMessage/Content/classes.ts 0 → 100644 +6 −0 Original line number Original line Diff line number Diff line import { css } from '@emotion/css' export const alignRight = css` display: flex; justify-content: flex-end; ` frontend/src/actionlog/InjectMessage/Content/index.tsx +4 −0 Original line number Original line Diff line number Diff line Loading @@ -41,10 +41,12 @@ const Content: FC<ContentProps> = ({ teamId={teamId} teamId={teamId} exerciseId={exerciseId} exerciseId={exerciseId} inInstructor={inInstructor} inInstructor={inInstructor} onClose={onClose} /> /> ) ) case 'ToolDetailsType': case 'ToolDetailsType': return ( return ( // can't be in overlay, so no onClose <ToolContent <ToolContent details={actionLog.details} details={actionLog.details} teamId={teamId} teamId={teamId} Loading @@ -55,6 +57,7 @@ const Content: FC<ContentProps> = ({ case 'TeamQuestionnaireStateType': { case 'TeamQuestionnaireStateType': { const teamState = actionLog.details const teamState = actionLog.details return inInstructor ? ( return inInstructor ? ( // can't be in overlay, so no onClose <InstructorQuestionnaire <InstructorQuestionnaire teamStateId={teamState.id} teamStateId={teamState.id} exerciseId={exerciseId} exerciseId={exerciseId} Loading Loading @@ -82,6 +85,7 @@ const Content: FC<ContentProps> = ({ teamId={teamId} teamId={teamId} exerciseId={exerciseId} exerciseId={exerciseId} inInstructor={inInstructor} inInstructor={inInstructor} onClose={onClose} /> /> ) ) default: default: Loading shared/popup/PopupEngine.tsx +18 −1 Original line number Original line Diff line number Diff line Loading @@ -12,6 +12,23 @@ import type { const MIN_TO_S = 60 const MIN_TO_S = 60 const S_TO_MS = 1000 const S_TO_MS = 1000 const timedFormatter = (secondsLeft: number) => { if (secondsLeft < 10) { return `${secondsLeft} ${secondsLeft > 1 ? 'seconds' : 'second'}` } if (secondsLeft < 30) { return 'less than 30 seconds' } if (secondsLeft < 60) { return 'less than a minute' } const hours = Math.floor(secondsLeft / 3600) const minutes = Math.floor(secondsLeft / 60) % 60 const hourString = `${hours} ${hours > 1 ? 'hours' : 'hour'}` const minuteString = `${minutes % 60} ${minutes % 60 > 1 ? 'minutes' : 'minute'}` return `${hours > 0 ? `${hourString} ` : ''}${minutes > 0 ? minuteString : ''}` } const PopupEngine = ({ children }: PropsWithChildren) => { const PopupEngine = ({ children }: PropsWithChildren) => { const [queue, setQueue] = useState<ShowPopupProps[]>([]) const [queue, setQueue] = useState<ShowPopupProps[]>([]) Loading Loading @@ -87,7 +104,7 @@ const PopupEngine = ({ children }: PropsWithChildren) => { {getContent(handleClose)} {getContent(handleClose)} </DialogBody> </DialogBody> <DialogFooter> <DialogFooter> <span>{`The popup will close in ${new Date(secondsLeft * S_TO_MS).toISOString().substring(11, 19)}`}</span> <span>{`The popup will close in ${timedFormatter(secondsLeft)}`}</span> </DialogFooter> </DialogFooter> </Dialog> </Dialog> ) ) Loading Loading
frontend/src/actionlog/InjectMessage/Content/EmailContent.tsx +9 −0 Original line number Original line Diff line number Diff line import ContentComponent from '@/components/ContentComponent' import ContentComponent from '@/components/ContentComponent' import { Button } from '@blueprintjs/core' import { css } from '@emotion/css' import { css } from '@emotion/css' import type { EmailDetails } from '@inject/graphql/fragment-types' import type { EmailDetails } from '@inject/graphql/fragment-types' import type { FC } from 'react' import type { FC } from 'react' import { alignRight } from './classes' const wrapper = css` const wrapper = css` display: flex; display: flex; Loading @@ -14,6 +16,7 @@ interface EmailContentProps { teamId: string teamId: string exerciseId: string exerciseId: string inInstructor: boolean inInstructor: boolean onClose?: () => void } } const EmailContent: FC<EmailContentProps> = ({ const EmailContent: FC<EmailContentProps> = ({ Loading @@ -21,6 +24,7 @@ const EmailContent: FC<EmailContentProps> = ({ teamId, teamId, exerciseId, exerciseId, inInstructor, inInstructor, onClose, }) => ( }) => ( <div className={wrapper}> <div className={wrapper}> <ContentComponent <ContentComponent Loading @@ -29,6 +33,11 @@ const EmailContent: FC<EmailContentProps> = ({ exerciseId={exerciseId} exerciseId={exerciseId} inInstructor={inInstructor} inInstructor={inInstructor} /> /> {onClose && ( <div className={alignRight}> <Button intent='primary' text='Close' onClick={onClose} /> </div> )} </div> </div> ) ) Loading
frontend/src/actionlog/InjectMessage/Content/InjectContent.tsx +8 −1 Original line number Original line Diff line number Diff line Loading @@ -13,6 +13,7 @@ import useBlockableMutation from '@inject/graphql/utils/useBlockableMutation' import { timedFormatter } from '@inject/shared/components/StyledTag/Timestamp' import { timedFormatter } from '@inject/shared/components/StyledTag/Timestamp' import type { FC } from 'react' import type { FC } from 'react' import { useMemo } from 'react' import { useMemo } from 'react' import { alignRight } from './classes' const wrapper = css` const wrapper = css` display: flex; display: flex; Loading Loading @@ -82,7 +83,7 @@ const InjectContent: FC<InjectContentProps> = ({ exerciseId={exerciseId} exerciseId={exerciseId} inInstructor={inInstructor} inInstructor={inInstructor} /> /> {confirmation && ( {confirmation ? ( <Done done={!!confirmed} title={title}> <Done done={!!confirmed} title={title}> <Button <Button intent='primary' intent='primary' Loading @@ -93,6 +94,12 @@ const InjectContent: FC<InjectContentProps> = ({ title={title} title={title} /> /> </Done> </Done> ) : ( onClose && ( <div className={alignRight}> <Button intent='primary' text='Close' onClick={onClose} /> </div> ) )} )} </div> </div> ) ) Loading
frontend/src/actionlog/InjectMessage/Content/classes.ts 0 → 100644 +6 −0 Original line number Original line Diff line number Diff line import { css } from '@emotion/css' export const alignRight = css` display: flex; justify-content: flex-end; `
frontend/src/actionlog/InjectMessage/Content/index.tsx +4 −0 Original line number Original line Diff line number Diff line Loading @@ -41,10 +41,12 @@ const Content: FC<ContentProps> = ({ teamId={teamId} teamId={teamId} exerciseId={exerciseId} exerciseId={exerciseId} inInstructor={inInstructor} inInstructor={inInstructor} onClose={onClose} /> /> ) ) case 'ToolDetailsType': case 'ToolDetailsType': return ( return ( // can't be in overlay, so no onClose <ToolContent <ToolContent details={actionLog.details} details={actionLog.details} teamId={teamId} teamId={teamId} Loading @@ -55,6 +57,7 @@ const Content: FC<ContentProps> = ({ case 'TeamQuestionnaireStateType': { case 'TeamQuestionnaireStateType': { const teamState = actionLog.details const teamState = actionLog.details return inInstructor ? ( return inInstructor ? ( // can't be in overlay, so no onClose <InstructorQuestionnaire <InstructorQuestionnaire teamStateId={teamState.id} teamStateId={teamState.id} exerciseId={exerciseId} exerciseId={exerciseId} Loading Loading @@ -82,6 +85,7 @@ const Content: FC<ContentProps> = ({ teamId={teamId} teamId={teamId} exerciseId={exerciseId} exerciseId={exerciseId} inInstructor={inInstructor} inInstructor={inInstructor} onClose={onClose} /> /> ) ) default: default: Loading
shared/popup/PopupEngine.tsx +18 −1 Original line number Original line Diff line number Diff line Loading @@ -12,6 +12,23 @@ import type { const MIN_TO_S = 60 const MIN_TO_S = 60 const S_TO_MS = 1000 const S_TO_MS = 1000 const timedFormatter = (secondsLeft: number) => { if (secondsLeft < 10) { return `${secondsLeft} ${secondsLeft > 1 ? 'seconds' : 'second'}` } if (secondsLeft < 30) { return 'less than 30 seconds' } if (secondsLeft < 60) { return 'less than a minute' } const hours = Math.floor(secondsLeft / 3600) const minutes = Math.floor(secondsLeft / 60) % 60 const hourString = `${hours} ${hours > 1 ? 'hours' : 'hour'}` const minuteString = `${minutes % 60} ${minutes % 60 > 1 ? 'minutes' : 'minute'}` return `${hours > 0 ? `${hourString} ` : ''}${minutes > 0 ? minuteString : ''}` } const PopupEngine = ({ children }: PropsWithChildren) => { const PopupEngine = ({ children }: PropsWithChildren) => { const [queue, setQueue] = useState<ShowPopupProps[]>([]) const [queue, setQueue] = useState<ShowPopupProps[]>([]) Loading Loading @@ -87,7 +104,7 @@ const PopupEngine = ({ children }: PropsWithChildren) => { {getContent(handleClose)} {getContent(handleClose)} </DialogBody> </DialogBody> <DialogFooter> <DialogFooter> <span>{`The popup will close in ${new Date(secondsLeft * S_TO_MS).toISOString().substring(11, 19)}`}</span> <span>{`The popup will close in ${timedFormatter(secondsLeft)}`}</span> </DialogFooter> </DialogFooter> </Dialog> </Dialog> ) ) Loading