Skip to content

Commit

Permalink
428 points (#463)
Browse files Browse the repository at this point in the history
* Prevented refresh when uploading solutions

* Removed debug prints
  • Loading branch information
vgeffer authored Nov 23, 2024
1 parent c44da93 commit af7a103
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 116 deletions.
285 changes: 170 additions & 115 deletions src/components/ProblemAdministration/ProblemAdministration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import {DropzoneOptions, useDropzone} from 'react-dropzone'
import {ProblemWithSolutions, SemesterWithProblems, SolutionAdministration} from '@/types/api/competition'
import {PageTitleContainer} from '@/utils/PageTitleContainer'
import {useHasPermissions} from '@/utils/useHasPermissions'
import {useNavigationTrap} from '@/utils/useNavigationTrap'

import {Button} from '../Clickable/Button'
import {Link} from '../Clickable/Link'
import {Dialog} from '../Dialog/Dialog'
import {FileDropZone} from '../FileDropZone/FileDropZone'
import {FileUploader} from '../FileUploader/FileUploader'
import {Latex} from '../Latex/Latex'
Expand All @@ -25,6 +27,16 @@ export const ProblemAdministration: FC = () => {

const problemId = params && params[0]

const [isDirty, setIsDirty] = useState(false)

const [exitDialogOpen, setExitDialogOpen] = useState(false)
const {continueNavigation} = useNavigationTrap({
shouldBlockNavigation: isDirty,
onNavigate: () => {
setExitDialogOpen(true)
},
})

const {
data: problemData,
refetch: refetchProblem,
Expand Down Expand Up @@ -80,6 +92,23 @@ export const ProblemAdministration: FC = () => {
// nie je to ale "deep copy" - data[index] je tiez referencia na povodny objekt, treba ho skopirovat
data[index] = {...data[index], score: newScore}
setSolutions(data)
setIsDirty(true)
}

const updateSolution = (index: number) => {
// array v javascripte je objekt s referenciou, pre skopirovanie odpojene od originalneho objektu treba vytvorit novy array
const data = [...(solutions ?? [])]
// nie je to ale "deep copy" - data[index] je tiez referencia na povodny objekt, treba ho skopirovat
data[index] = {...data[index], solution: 'uploaded'}
setSolutions(data)
}

const updateCorrectedSolution = (index: number) => {
// array v javascripte je objekt s referenciou, pre skopirovanie odpojene od originalneho objektu treba vytvorit novy array
const data = [...(solutions ?? [])]
// nie je to ale "deep copy" - data[index] je tiez referencia na povodny objekt, treba ho skopirovat
data[index] = {...data[index], corrected_solution: 'uploaded'}
setSolutions(data)
}

const {mutate: uploadZipFile, error: uploadZipFileError} = useMutation({
Expand Down Expand Up @@ -124,129 +153,155 @@ export const ProblemAdministration: FC = () => {
if (problemId === undefined || !problem)
return <Typography>Nevalidné číslo úlohy (problemId) v URL alebo ju proste nevieme fetchnúť z BE.</Typography>

const handleSavePoints = () => uploadPoints(problemId)
const handleSavePoints = () => {
setIsDirty(false)
uploadPoints(problemId)
}

return (
<Stack gap={2}>
<Stack direction="row" justifyContent="space-between">
<Typography variant="h2">Opravovanie {problem.order}. úlohy</Typography>

<Link variant="button2" href={`/strom/admin/opravovanie/${semesterUrl}`}>
Späť na semester
</Link>
</Stack>
<>
<Dialog
open={exitDialogOpen}
title="Neuložené zmeny"
contentText="Máš neuložené zmeny. Naozaj chceš opustiť stránku?"
actions={
<>
<Button variant="button2" onClick={continueNavigation}>
Opustiť stránku
</Button>
<Button
variant="button2"
onClick={() => {
setExitDialogOpen(false)
}}
>
Zostať na stránke
</Button>
</>
}
/>
<Stack gap={2}>
<Stack direction="row" justifyContent="space-between">
<Typography variant="h2">Opravovanie {problem.order}. úlohy</Typography>

<Latex>{problem.text ?? 'Načítavam...'}</Latex>

<div className={styles.row}>
<Typography variant="body1" component="div">
Vzorové riešenie:
</Typography>
{problem.solution_pdf ? (
<a href={problem.solution_pdf} target="_blank" rel="noreferrer" className={styles.icon}>
<FormatAlignJustify />
</a>
) : (
<div className={styles.iconDisabled}>
<FormatAlignJustify />
</div>
)}
<FileUploader
uploadLink={`/api/competition/problem/${problemId}/upload-model-solution`}
refetch={refetchProblem}
/>
</div>
<Link variant="button2" href={`/strom/admin/opravovanie/${semesterUrl}`}>
Späť na semester
</Link>
</Stack>

<Stack alignItems="end">
<Link variant="button2" href={`/api/competition/problem/${problemId}/download-solutions`}>
Stiahnuť riešenia
</Link>
</Stack>
<Latex>{problem.text ?? 'Načítavam...'}</Latex>

<FileDropZone
getRootProps={getRootProps}
getInputProps={getInputProps}
text="Vlož opravené riešenia vo formáte zip"
/>
{uploadZipFileError && (
<>
<Typography>Chyby pri nahrávaní ZIPka:</Typography>
<Typography sx={{whiteSpace: 'pre-line'}}>{uploadZipFileErrors}</Typography>
</>
)}

<form>
<div className={styles.table}>
<div className={styles.tableHeader}>
<div>Riešiteľ</div>
<div className={styles.centerCell}>Body</div>
<div className={styles.centerCell}>Riešenie</div>
<div className={styles.centerCell}>Opravené</div>
</div>
{solutions?.map((solution, index) => (
<div key={solution.id} className={styles.tableRow}>
<div>
{solution.semester_registration?.profile.first_name} {solution.semester_registration?.profile.last_name}
</div>
<div className={styles.centerCell}>
<input
type="text"
pattern="[0-9]"
value={solution.score ?? ''}
onChange={(event) => updatePoints(index, event.target.value)}
className={styles.input}
/>
</div>
<div className={styles.centerCell}>
{solution.solution ? (
<a
href={`/api/competition/solution/${solution.id}/file-solution`}
target="_blank"
rel="noreferrer"
className={styles.icon}
>
<FormatAlignJustify />
</a>
) : (
<div className={styles.iconDisabled}>
<FormatAlignJustify />
</div>
)}
<FileUploader
uploadLink={`/api/competition/solution/${solution.id}/upload-solution-file`}
refetch={refetchProblem}
/>
</div>
<div className={styles.centerCell}>
{solution.corrected_solution ? (
<a
href={`/api/competition/solution/${solution.id}/file-corrected`}
target="_blank"
rel="noreferrer"
className={styles.icon}
>
<Grading />
</a>
) : (
<div className={styles.iconDisabled}>
<Grading />
</div>
)}
<FileUploader
uploadLink={`/api/competition/solution/${solution.id}/upload-corrected-solution-file`}
refetch={refetchProblem}
/>
</div>
<div className={styles.row}>
<Typography variant="body1" component="div">
Vzorové riešenie:
</Typography>
{problem.solution_pdf ? (
<a href={problem.solution_pdf} target="_blank" rel="noreferrer" className={styles.icon}>
<FormatAlignJustify />
</a>
) : (
<div className={styles.iconDisabled}>
<FormatAlignJustify />
</div>
))}
)}
<FileUploader
uploadLink={`/api/competition/problem/${problemId}/upload-model-solution`}
refetch={refetchProblem}
/>
</div>

<Stack alignItems="end" mt={1.5}>
<Button variant="button2" onClick={handleSavePoints}>
Uložiť body
</Button>
<Stack alignItems="end">
<Link variant="button2" href={`/api/competition/problem/${problemId}/download-solutions`}>
Stiahnuť riešenia
</Link>
</Stack>
</form>
</Stack>

<FileDropZone
getRootProps={getRootProps}
getInputProps={getInputProps}
text="Vlož opravené riešenia vo formáte zip"
/>
{uploadZipFileError && (
<>
<Typography>Chyby pri nahrávaní ZIPka:</Typography>
<Typography sx={{whiteSpace: 'pre-line'}}>{uploadZipFileErrors}</Typography>
</>
)}

<form>
<div className={styles.table}>
<div className={styles.tableHeader}>
<div>Riešiteľ</div>
<div className={styles.centerCell}>Body</div>
<div className={styles.centerCell}>Riešenie</div>
<div className={styles.centerCell}>Opravené</div>
</div>
{solutions?.map((solution, index) => (
<div key={solution.id} className={styles.tableRow}>
<div>
{solution.semester_registration?.profile.first_name}{' '}
{solution.semester_registration?.profile.last_name}
</div>
<div className={styles.centerCell}>
<input
type="text"
pattern="[0-9]"
value={solution.score ?? ''}
onChange={(event) => updatePoints(index, event.target.value)}
className={styles.input}
/>
</div>
<div className={styles.centerCell}>
{solution.solution ? (
<a
href={`/api/competition/solution/${solution.id}/file-solution`}
target="_blank"
rel="noreferrer"
className={styles.icon}
>
<FormatAlignJustify />
</a>
) : (
<div className={styles.iconDisabled}>
<FormatAlignJustify />
</div>
)}
<FileUploader
uploadLink={`/api/competition/solution/${solution.id}/upload-solution-file`}
refetch={() => updateSolution(index)}
/>
</div>
<div className={styles.centerCell}>
{solution.corrected_solution ? (
<a
href={`/api/competition/solution/${solution.id}/file-corrected`}
target="_blank"
rel="noreferrer"
className={styles.icon}
>
<Grading />
</a>
) : (
<div className={styles.iconDisabled}>
<Grading />
</div>
)}
<FileUploader
uploadLink={`/api/competition/solution/${solution.id}/upload-corrected-solution-file`}
refetch={() => updateCorrectedSolution(index)}
/>
</div>
</div>
))}
</div>

<Stack alignItems="end" mt={1.5}>
<Button variant="button2" onClick={handleSavePoints}>
Uložiť body
</Button>
</Stack>
</form>
</Stack>
</>
)
}
2 changes: 1 addition & 1 deletion src/utils/useNavigationTrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const useNavigationTrap = ({shouldBlockNavigation, onNavigate}: Navigatio
}

const pageExit = (e: BeforeUnloadEvent) => {
e.preventDefault()
if (shouldBlockNavigation) e.preventDefault()
}

router.events.on('routeChangeStart', pageNavigate)
Expand Down

0 comments on commit af7a103

Please sign in to comment.