Enhance ExerciseFormPageRoot with save and close functionality
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Test Suite / pytest-backend (push) Successful in 38s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 14s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m14s
Test Suite / pytest-backend (pull_request) Successful in 35s
Test Suite / lint-backend (pull_request) Successful in 0s
Test Suite / build-frontend (pull_request) Successful in 12s
Test Suite / k6 /health Baseline (pull_request) Successful in 33s
Test Suite / playwright-tests (pull_request) Successful in 1m13s
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Test Suite / pytest-backend (push) Successful in 38s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 14s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m14s
Test Suite / pytest-backend (pull_request) Successful in 35s
Test Suite / lint-backend (pull_request) Successful in 0s
Test Suite / build-frontend (pull_request) Successful in 12s
Test Suite / k6 /health Baseline (pull_request) Successful in 33s
Test Suite / playwright-tests (pull_request) Successful in 1m13s
- Added a new `handleSaveAndClose` function to allow users to save and navigate back to the exercise list. - Updated `performSaveAttempt` to accept a `closeAfter` parameter for conditional navigation. - Refactored form submission handling to include separate actions for saving and saving with closure. - Integrated `PageFormEditorChrome` for improved layout and user experience, including a back navigation option.
This commit is contained in:
parent
d19a1061d8
commit
e50c18f92e
|
|
@ -26,6 +26,7 @@ import { COMBINATION_ARCHETYPE_OPTIONS, ARCHETYPE_DEFAULT_REP_SERIES_COUNT, defa
|
||||||
import { readSlotProfilesV1, normalizeAdvanceMode, parseComboRepSeriesCountUi } from '../../utils/combinationMethodProfileUi'
|
import { readSlotProfilesV1, normalizeAdvanceMode, parseComboRepSeriesCountUi } from '../../utils/combinationMethodProfileUi'
|
||||||
import { GripVertical } from 'lucide-react'
|
import { GripVertical } from 'lucide-react'
|
||||||
import UnsavedChangesPrompt from '../UnsavedChangesPrompt'
|
import UnsavedChangesPrompt from '../UnsavedChangesPrompt'
|
||||||
|
import PageFormEditorChrome from '../PageFormEditorChrome'
|
||||||
import { useBeforeUnloadWhen, useUnsavedChangesBlocker } from '../../hooks/useUnsavedChangesBlocker'
|
import { useBeforeUnloadWhen, useUnsavedChangesBlocker } from '../../hooks/useUnsavedChangesBlocker'
|
||||||
|
|
||||||
const INTENSITY_OPTIONS = [
|
const INTENSITY_OPTIONS = [
|
||||||
|
|
@ -836,7 +837,7 @@ function ExerciseFormPageRoot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const performSaveAttempt = useCallback(
|
const performSaveAttempt = useCallback(
|
||||||
async ({ fromUnsavedDialog = false } = {}) => {
|
async ({ fromUnsavedDialog = false, closeAfter = false } = {}) => {
|
||||||
if (!formData.title || formData.title.trim().length < 3) {
|
if (!formData.title || formData.title.trim().length < 3) {
|
||||||
toast.error('Titel mindestens 3 Zeichen')
|
toast.error('Titel mindestens 3 Zeichen')
|
||||||
return false
|
return false
|
||||||
|
|
@ -940,12 +941,15 @@ function ExerciseFormPageRoot() {
|
||||||
setVariants((ex.variants || []).map(apiVariantToRow))
|
setVariants((ex.variants || []).map(apiVariantToRow))
|
||||||
setFormDirty(false)
|
setFormDirty(false)
|
||||||
toast.success('Gespeichert.')
|
toast.success('Gespeichert.')
|
||||||
|
if (closeAfter) navigate('/exercises')
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
const created = await api.createExercise(payload)
|
const created = await api.createExercise(payload)
|
||||||
setFormDirty(false)
|
setFormDirty(false)
|
||||||
toast.success('Übung angelegt.')
|
toast.success('Übung angelegt.')
|
||||||
if (!fromUnsavedDialog) {
|
if (closeAfter) {
|
||||||
|
navigate('/exercises')
|
||||||
|
} else if (!fromUnsavedDialog) {
|
||||||
navigate(`/exercises/${created.id}/edit`, { replace: true })
|
navigate(`/exercises/${created.id}/edit`, { replace: true })
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
@ -959,10 +963,39 @@ function ExerciseFormPageRoot() {
|
||||||
[exerciseId, formData, isEdit, navigate, toast],
|
[exerciseId, formData, isEdit, navigate, toast],
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = useCallback(
|
||||||
e.preventDefault()
|
async (e) => {
|
||||||
await performSaveAttempt({ fromUnsavedDialog: false })
|
e?.preventDefault?.()
|
||||||
}
|
await performSaveAttempt({ fromUnsavedDialog: false, closeAfter: false })
|
||||||
|
},
|
||||||
|
[performSaveAttempt],
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleSaveAndClose = useCallback(
|
||||||
|
async (e) => {
|
||||||
|
e?.preventDefault?.()
|
||||||
|
await performSaveAttempt({ fromUnsavedDialog: false, closeAfter: true })
|
||||||
|
},
|
||||||
|
[performSaveAttempt],
|
||||||
|
)
|
||||||
|
|
||||||
|
const goBackToList = useCallback(() => {
|
||||||
|
navigate('/exercises')
|
||||||
|
}, [navigate])
|
||||||
|
|
||||||
|
const actionConfig = useMemo(
|
||||||
|
() => ({
|
||||||
|
formId: 'exercise-form',
|
||||||
|
saving,
|
||||||
|
isNew: !isEdit,
|
||||||
|
onSave: handleSubmit,
|
||||||
|
onSaveAndClose: handleSaveAndClose,
|
||||||
|
onCancel: goBackToList,
|
||||||
|
showSave: true,
|
||||||
|
showSaveAndClose: true,
|
||||||
|
}),
|
||||||
|
[saving, isEdit, handleSubmit, handleSaveAndClose, goBackToList],
|
||||||
|
)
|
||||||
|
|
||||||
const handleUnsavedDialogSave = async () => {
|
const handleUnsavedDialogSave = async () => {
|
||||||
const ok = await performSaveAttempt({ fromUnsavedDialog: true })
|
const ok = await performSaveAttempt({ fromUnsavedDialog: true })
|
||||||
|
|
@ -1162,27 +1195,28 @@ function ExerciseFormPageRoot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: '12px' }} className="app-page">
|
<PageFormEditorChrome
|
||||||
<div style={{ marginBottom: '12px' }}>
|
testId="exercise-form-page"
|
||||||
<button type="button" className="btn btn-secondary" onClick={() => navigate('/exercises')}>
|
title={isEdit ? 'Übung bearbeiten' : 'Neue Übung'}
|
||||||
← Übersicht
|
backTo="/exercises"
|
||||||
</button>
|
backLabel="Übersicht"
|
||||||
{isEdit && (
|
actionConfig={actionConfig}
|
||||||
<button
|
>
|
||||||
type="button"
|
{isEdit ? (
|
||||||
|
<p style={{ margin: '0 0 12px' }}>
|
||||||
|
<Link
|
||||||
|
to={`/exercises/${exerciseId}`}
|
||||||
|
state={{ fromExerciseEdit: true }}
|
||||||
className="btn btn-secondary"
|
className="btn btn-secondary"
|
||||||
style={{ marginLeft: '8px' }}
|
style={{ fontSize: '0.875rem' }}
|
||||||
onClick={() => navigate(`/exercises/${exerciseId}`, { state: { fromExerciseEdit: true } })}
|
|
||||||
>
|
>
|
||||||
Ansehen
|
Ansehen
|
||||||
</button>
|
</Link>
|
||||||
)}
|
</p>
|
||||||
</div>
|
) : null}
|
||||||
|
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<h1 style={{ marginTop: 0, fontSize: '1.25rem' }}>{isEdit ? 'Übung bearbeiten' : 'Neue Übung'}</h1>
|
<form id="exercise-form" onSubmit={handleSubmit}>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit}>
|
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
<label className="form-label">Titel *</label>
|
<label className="form-label">Titel *</label>
|
||||||
<input
|
<input
|
||||||
|
|
@ -1943,12 +1977,6 @@ function ExerciseFormPageRoot() {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<div style={{ marginTop: '16px' }}>
|
|
||||||
<button type="submit" className="btn btn-primary" disabled={saving}>
|
|
||||||
{saving ? 'Speichern…' : isEdit ? 'Speichern' : 'Anlegen & weiter'}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -2439,8 +2467,9 @@ function ExerciseFormPageRoot() {
|
||||||
isBusy={saving}
|
isBusy={saving}
|
||||||
onSave={handleUnsavedDialogSave}
|
onSave={handleUnsavedDialogSave}
|
||||||
onDiscardWithoutSave={() => setFormDirty(false)}
|
onDiscardWithoutSave={() => setFormDirty(false)}
|
||||||
|
detail="Du hast ungespeicherte Änderungen vorgenommen. Möchtest du die Seite wirklich verlassen?"
|
||||||
/>
|
/>
|
||||||
</div>
|
</PageFormEditorChrome>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user