Loading frontend/src/components/ExerciseList/ExerciseButtons/NotesButton/index.tsx +11 −40 Original line number Diff line number Diff line import type { Intent } from '@blueprintjs/core' import { Button, Dialog, DialogBody } from '@blueprintjs/core' import { GetInstructorNotes, useTypedQuery } from '@inject/graphql' import type { ExerciseSimple } from '@inject/graphql' import { useTranslationFrontend } from '@inject/locale' import { CenteredSpinner, dialogBody, variableHeightMaximizedDialog, } from '@inject/shared' import { dialogBody, variableHeightMaximizedDialog } from '@inject/shared' import type { NavigateOptions } from '@tanstack/react-router' import { useState, type FC } from 'react' import { AttachmentsRow } from '../../../AttachmentsRow' import { RenderedContent } from '../../../RenderedContent' import { InstructorNotesComponent } from '../../../InstructorNotesComponent' interface NotesButtonProps { exerciseId: string exercise: ExerciseSimple intent?: Intent getFileLink: (fileId: string) => NavigateOptions } export const NotesButton: FC<NotesButtonProps> = ({ exerciseId, exercise, intent, getFileLink, }) => { const [dialogOpen, setDialogOpen] = useState(false) const { t } = useTranslationFrontend() const [{ data: instructorNotesData, fetching }] = useTypedQuery({ query: GetInstructorNotes, variables: { exerciseId }, }) if (fetching || !instructorNotesData?.exerciseId) { return <CenteredSpinner /> } return ( <> <Button Loading @@ -48,32 +35,16 @@ export const NotesButton: FC<NotesButtonProps> = ({ onClose={() => setDialogOpen(false)} title={ <span title={`${t('instructorNotes.title')} ${instructorNotesData.exerciseId.name}`} >{`${t('instructorNotes.title')} - ${instructorNotesData.exerciseId.name}`}</span> title={`${t('instructorNotes.title')} ${exercise.name}`} >{`${t('instructorNotes.title')} - ${exercise.name}`}</span> } className={variableHeightMaximizedDialog} > <DialogBody className={dialogBody}> {instructorNotesData && instructorNotesData.exerciseId.config.instructorNotes ? ( <> <RenderedContent renderedContent={ instructorNotesData.exerciseId.config.instructorNotes.rendered } exerciseId={exerciseId} /> <AttachmentsRow attachments={ instructorNotesData.exerciseId.config.instructorNotes .attachments } <InstructorNotesComponent exerciseId={exercise.id} getFileLink={getFileLink} /> </> ) : ( <p>{t('instructorNotes.notFound')}</p> )} </DialogBody> </Dialog> </> Loading frontend/src/components/ExerciseList/ExerciseButtons/index.tsx +1 −1 Original line number Diff line number Diff line Loading @@ -71,7 +71,7 @@ export const ExerciseButtons: FC<ExerciseButtonsProps> = ({ <InfoButton intent={intent} exerciseId={exercise.id} /> <NotesButton intent={intent} exerciseId={exercise.id} exercise={exercise} getFileLink={getFileLink} /> </ButtonGroup> Loading frontend/src/components/InstructorNotesComponent/index.tsx 0 → 100644 +56 −0 Original line number Diff line number Diff line import { NonIdealState } from '@blueprintjs/core' import { css } from '@emotion/css' import { GetInstructorNotes, useTypedQuery } from '@inject/graphql' import { useTranslationFrontend } from '@inject/locale' import type { NavigateOptions } from '@tanstack/react-router' import type { FC } from 'react' import ContentComponent from '../ContentComponent' interface InstructorNotesComponentProps { exerciseId: string getFileLink: (fileId: string) => NavigateOptions } export const InstructorNotesComponent: FC<InstructorNotesComponentProps> = ({ exerciseId, getFileLink, }) => { const { t } = useTranslationFrontend() const [{ data: instructorNotesData }] = useTypedQuery({ query: GetInstructorNotes, variables: { exerciseId }, pause: !exerciseId, }) const instructorNotes = instructorNotesData?.exerciseId.config.instructorNotes if ( !instructorNotes || (!instructorNotes.rendered && !instructorNotes.attachments.length) ) { return ( <NonIdealState className={css` display: flex; justify-content: center; align-items: center; height: 100%; overflow: auto; padding: 2rem; `} icon='book' title={t('instructorNotes.notFound')} description={t('instructorNotes.notFoundDescription')} /> ) } return ( <ContentComponent content={instructorNotes} exerciseId={exerciseId} inInstructor getFileLink={getFileLink} /> ) } frontend/src/routes/_protected/instructor/$exerciseId/instructor-notes.tsx +2 −27 Original line number Diff line number Diff line import { NonIdealState } from '@blueprintjs/core' import { css } from '@emotion/css' import { GetInstructorNotes, useTypedQuery } from '@inject/graphql' import { useTranslationFrontend } from '@inject/locale' import { Container } from '@inject/shared' import { createFileRoute } from '@tanstack/react-router' import ContentComponent from '../../../../components/ContentComponent' import { InstructorNotesComponent } from '../../../../components/InstructorNotesComponent' import { InstructorFilePageRoute } from './file.$fileId' const InstructorNotesPage = () => { const { exerciseId } = Route.useParams() const { t } = useTranslationFrontend() const [{ data: instructorNotesData }] = useTypedQuery({ query: GetInstructorNotes, variables: { exerciseId: exerciseId || '' }, }) const instructorNotes = instructorNotesData?.exerciseId.config.instructorNotes if ( !instructorNotes || (!instructorNotes.rendered && !instructorNotes.attachments) ) { return ( <NonIdealState className={css` padding-top: 0.5rem; `} icon='book' title={t('instructorNotes.notFound')} /> ) } return ( <Container className={css` Loading @@ -39,10 +16,8 @@ const InstructorNotesPage = () => { `} > <h3>{t('instructorNotes.title')}:</h3> <ContentComponent content={instructorNotes} <InstructorNotesComponent exerciseId={exerciseId} inInstructor getFileLink={fileId => ({ to: InstructorFilePageRoute.to, params: { Loading locale/resources/cs/frontend.json +1 −0 Original line number Diff line number Diff line Loading @@ -435,6 +435,7 @@ }, "instructorNotes": { "notFound": "Poznámky pro instruktory nebyly poskytnuty.", "notFoundDescription": "Pro toto cvičení nejsou k dispozici žádné poznámky pro instruktory.", "title": "Poznámky pro instruktory" }, "teamOverview": { Loading Loading
frontend/src/components/ExerciseList/ExerciseButtons/NotesButton/index.tsx +11 −40 Original line number Diff line number Diff line import type { Intent } from '@blueprintjs/core' import { Button, Dialog, DialogBody } from '@blueprintjs/core' import { GetInstructorNotes, useTypedQuery } from '@inject/graphql' import type { ExerciseSimple } from '@inject/graphql' import { useTranslationFrontend } from '@inject/locale' import { CenteredSpinner, dialogBody, variableHeightMaximizedDialog, } from '@inject/shared' import { dialogBody, variableHeightMaximizedDialog } from '@inject/shared' import type { NavigateOptions } from '@tanstack/react-router' import { useState, type FC } from 'react' import { AttachmentsRow } from '../../../AttachmentsRow' import { RenderedContent } from '../../../RenderedContent' import { InstructorNotesComponent } from '../../../InstructorNotesComponent' interface NotesButtonProps { exerciseId: string exercise: ExerciseSimple intent?: Intent getFileLink: (fileId: string) => NavigateOptions } export const NotesButton: FC<NotesButtonProps> = ({ exerciseId, exercise, intent, getFileLink, }) => { const [dialogOpen, setDialogOpen] = useState(false) const { t } = useTranslationFrontend() const [{ data: instructorNotesData, fetching }] = useTypedQuery({ query: GetInstructorNotes, variables: { exerciseId }, }) if (fetching || !instructorNotesData?.exerciseId) { return <CenteredSpinner /> } return ( <> <Button Loading @@ -48,32 +35,16 @@ export const NotesButton: FC<NotesButtonProps> = ({ onClose={() => setDialogOpen(false)} title={ <span title={`${t('instructorNotes.title')} ${instructorNotesData.exerciseId.name}`} >{`${t('instructorNotes.title')} - ${instructorNotesData.exerciseId.name}`}</span> title={`${t('instructorNotes.title')} ${exercise.name}`} >{`${t('instructorNotes.title')} - ${exercise.name}`}</span> } className={variableHeightMaximizedDialog} > <DialogBody className={dialogBody}> {instructorNotesData && instructorNotesData.exerciseId.config.instructorNotes ? ( <> <RenderedContent renderedContent={ instructorNotesData.exerciseId.config.instructorNotes.rendered } exerciseId={exerciseId} /> <AttachmentsRow attachments={ instructorNotesData.exerciseId.config.instructorNotes .attachments } <InstructorNotesComponent exerciseId={exercise.id} getFileLink={getFileLink} /> </> ) : ( <p>{t('instructorNotes.notFound')}</p> )} </DialogBody> </Dialog> </> Loading
frontend/src/components/ExerciseList/ExerciseButtons/index.tsx +1 −1 Original line number Diff line number Diff line Loading @@ -71,7 +71,7 @@ export const ExerciseButtons: FC<ExerciseButtonsProps> = ({ <InfoButton intent={intent} exerciseId={exercise.id} /> <NotesButton intent={intent} exerciseId={exercise.id} exercise={exercise} getFileLink={getFileLink} /> </ButtonGroup> Loading
frontend/src/components/InstructorNotesComponent/index.tsx 0 → 100644 +56 −0 Original line number Diff line number Diff line import { NonIdealState } from '@blueprintjs/core' import { css } from '@emotion/css' import { GetInstructorNotes, useTypedQuery } from '@inject/graphql' import { useTranslationFrontend } from '@inject/locale' import type { NavigateOptions } from '@tanstack/react-router' import type { FC } from 'react' import ContentComponent from '../ContentComponent' interface InstructorNotesComponentProps { exerciseId: string getFileLink: (fileId: string) => NavigateOptions } export const InstructorNotesComponent: FC<InstructorNotesComponentProps> = ({ exerciseId, getFileLink, }) => { const { t } = useTranslationFrontend() const [{ data: instructorNotesData }] = useTypedQuery({ query: GetInstructorNotes, variables: { exerciseId }, pause: !exerciseId, }) const instructorNotes = instructorNotesData?.exerciseId.config.instructorNotes if ( !instructorNotes || (!instructorNotes.rendered && !instructorNotes.attachments.length) ) { return ( <NonIdealState className={css` display: flex; justify-content: center; align-items: center; height: 100%; overflow: auto; padding: 2rem; `} icon='book' title={t('instructorNotes.notFound')} description={t('instructorNotes.notFoundDescription')} /> ) } return ( <ContentComponent content={instructorNotes} exerciseId={exerciseId} inInstructor getFileLink={getFileLink} /> ) }
frontend/src/routes/_protected/instructor/$exerciseId/instructor-notes.tsx +2 −27 Original line number Diff line number Diff line import { NonIdealState } from '@blueprintjs/core' import { css } from '@emotion/css' import { GetInstructorNotes, useTypedQuery } from '@inject/graphql' import { useTranslationFrontend } from '@inject/locale' import { Container } from '@inject/shared' import { createFileRoute } from '@tanstack/react-router' import ContentComponent from '../../../../components/ContentComponent' import { InstructorNotesComponent } from '../../../../components/InstructorNotesComponent' import { InstructorFilePageRoute } from './file.$fileId' const InstructorNotesPage = () => { const { exerciseId } = Route.useParams() const { t } = useTranslationFrontend() const [{ data: instructorNotesData }] = useTypedQuery({ query: GetInstructorNotes, variables: { exerciseId: exerciseId || '' }, }) const instructorNotes = instructorNotesData?.exerciseId.config.instructorNotes if ( !instructorNotes || (!instructorNotes.rendered && !instructorNotes.attachments) ) { return ( <NonIdealState className={css` padding-top: 0.5rem; `} icon='book' title={t('instructorNotes.notFound')} /> ) } return ( <Container className={css` Loading @@ -39,10 +16,8 @@ const InstructorNotesPage = () => { `} > <h3>{t('instructorNotes.title')}:</h3> <ContentComponent content={instructorNotes} <InstructorNotesComponent exerciseId={exerciseId} inInstructor getFileLink={fileId => ({ to: InstructorFilePageRoute.to, params: { Loading
locale/resources/cs/frontend.json +1 −0 Original line number Diff line number Diff line Loading @@ -435,6 +435,7 @@ }, "instructorNotes": { "notFound": "Poznámky pro instruktory nebyly poskytnuty.", "notFoundDescription": "Pro toto cvičení nejsou k dispozici žádné poznámky pro instruktory.", "title": "Poznámky pro instruktory" }, "teamOverview": { Loading