Skip to content

Commit

Permalink
fix: confirmation modal and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mariojsnunes committed Jul 12, 2024
1 parent eee86ca commit a387fd8
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 144 deletions.
1 change: 1 addition & 0 deletions packages/components/src/ConfirmModal/ConfirmModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const ConfirmModal = (props: Props) => {
<Button
type="button"
variant="outline"
data-cy="Confirm.modal: Cancel"
onClick={() => props?.handleCancel()}
>
Cancel
Expand Down
18 changes: 3 additions & 15 deletions packages/cypress/src/integration/howto/write.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,6 @@ describe('[How To]', () => {
})

it('[Warning on leaving page]', () => {
const stub = cy.stub()
stub.returns(false)

cy.login(creatorEmail, creatorPassword)
cy.get('[data-cy=loader]').should('not.exist')
cy.step('Access the create-how-to')
Expand All @@ -347,22 +344,13 @@ describe('[How To]', () => {
.clear()
.type(expected.title)
.blur({ force: true })
cy.get('[data-cy=page-link][href*="/how-to"]')
.click()
.then(() => {
expect(stub.callCount).to.equal(1)
stub.resetHistory()
})
cy.get('[data-cy=page-link][href*="/how-to"]').click()
cy.get('[data-cy="Confirm.modal: Cancel"]').click()
cy.url().should('match', /\/how-to\/create$/)

cy.step('Clear title input')
cy.get('[data-cy=intro-title]').clear().blur({ force: true })
cy.get('[data-cy=page-link][href*="/how-to"]')
.click()
.then(() => {
expect(stub.callCount).to.equal(0)
stub.resetHistory()
})
cy.get('[data-cy=page-link][href*="/how-to"]').click()
cy.url().should('match', /\/how-to?/)
})
})
Expand Down
20 changes: 4 additions & 16 deletions packages/cypress/src/integration/research/write.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ describe('[Research]', () => {
There is an issue with cypress that can not type some of the start string failing the test
https://github.com/cypress-io/cypress/issues/3817
*/
cy.wait(500)
cy.wait(1000)
cy.get('[data-cy=intro-description]').type(expected.description).blur()

cy.step('New collaborators can be assigned to research')
Expand Down Expand Up @@ -228,9 +228,6 @@ describe('[Research]', () => {
})

it('[Warning on leaving page]', () => {
const stub = cy.stub()
stub.returns(false)

cy.login(researcherEmail, researcherPassword)
cy.step('Access the create research article')
cy.get('[data-cy=loader]').should('not.exist')
Expand All @@ -240,22 +237,13 @@ describe('[Research]', () => {
.clear()
.type('Create research article test')
.blur({ force: true })
cy.get('[data-cy=page-link][href*="/research"]')
.click()
.then(() => {
expect(stub.callCount).to.equal(1)
stub.resetHistory()
})
cy.get('[data-cy=page-link][href*="/research"]').click()
cy.get('[data-cy="Confirm.modal: Cancel"]').click()

cy.url().should('match', /\/research\/create$/)

cy.step('Clear title input')
cy.get('[data-cy=intro-title').clear().blur({ force: true })
cy.get('[data-cy=page-link][href*="/research"]')
.click()
.then(() => {
expect(stub.callCount).to.equal(0)
stub.resetHistory()
})
cy.url().should('match', /\/research?/)
})
})
Expand Down
46 changes: 13 additions & 33 deletions src/common/Form/UnsavedChangesDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,30 @@
import { memo, useState } from 'react'
import { FormSpy } from 'react-final-form'
import { useBlocker } from 'react-router'
import { ConfirmModal } from 'oa-components'

interface IProps {
uploadComplete?: boolean
message?: string
}

const CONFIRM_DIALOG_MSG =
'You have unsaved changes. Are you sure you want to leave this page?'

/**
* When places inside a react-final-form <Form> element watches for form pristine/dirty
* change and handles router and window confirmation if form contains changes
**/
export const UnsavedChangesDialog = memo((props: IProps) => {
// Use memo to only re-render if props change
const [formIsDirty, setFormIsDirty] = useState(false)
const shouldPromptUnsavedChanges = formIsDirty && !props.uploadComplete
const message = props.message || CONFIRM_DIALOG_MSG
type IProps = {
hasChanges: boolean
}

export const UnsavedChangesDialog = ({ hasChanges }: IProps) => {
const blocker = useBlocker(
({ currentLocation, nextLocation }) =>
shouldPromptUnsavedChanges &&
currentLocation.pathname !== nextLocation.pathname,
hasChanges && currentLocation.pathname !== nextLocation.pathname,
)

// Handle confirmaiton inside react route
return (
<>
<FormSpy
subscription={{ dirty: true }}
onChange={(form) => {
setFormIsDirty(form.dirty)
}}
render={() => null}
/>
<ConfirmModal
isOpen={blocker.state === 'blocked'}
message={message}
confirmButtonText="Yes"
handleCancel={() => blocker.reset && blocker.reset()}
handleConfirm={() => blocker.proceed && blocker.proceed()}
/>
</>
<ConfirmModal
isOpen={blocker.state === 'blocked'}
message={CONFIRM_DIALOG_MSG}
confirmButtonText="Yes"
handleCancel={() => blocker.reset && blocker.reset()}
handleConfirm={() => blocker.proceed && blocker.proceed()}
/>
)
})
UnsavedChangesDialog.displayName = 'UnsavedChangesDialog'
}
12 changes: 5 additions & 7 deletions src/pages/Howto/Content/Common/Howto.form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,7 @@ export const HowtoForm = observer((props: IProps) => {
/>
)}
<Form
onSubmit={(formValues, form) => {
onSubmit(formValues, form)
}}
onSubmit={async (formValues, form) => await onSubmit(formValues, form)}
initialValues={formValues}
mutators={{
setAllowDraftSaveTrue,
Expand All @@ -134,19 +132,19 @@ export const HowtoForm = observer((props: IProps) => {
validateOnBlur
decorators={[calculatedFields]}
render={({
dirty,
errors,
form,
handleSubmit,
hasValidationErrors,
submitFailed,
submitSucceeded,
submitting,
values,
}) => {
return (
<Flex mx={-2} bg={'inherit'} sx={{ flexWrap: 'wrap' }}>
<UnsavedChangesDialog
uploadComplete={howtoStore.uploadStatus.Complete}
/>
<Flex mx={-2} bg="inherit" sx={{ flexWrap: 'wrap' }}>
<UnsavedChangesDialog hasChanges={dirty && !submitSucceeded} />

<Flex
bg="inherit"
Expand Down
62 changes: 8 additions & 54 deletions src/pages/Research/Content/Common/Research.form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,6 @@ import ResearchFieldCategory from './ResearchCategorySelect'
import type { MainFormAction } from 'src/common/Form/types'
import type { IResearch } from 'src/models/research.models'

const CONFIRM_DIALOG_MSG =
'You have unsaved changes. Are you sure you want to leave this page?'
interface IState {
formSaved: boolean
dirty: boolean
showSubmitModal?: boolean
}
interface IProps {
'data-testid'?: string
formValues: any
Expand All @@ -64,11 +57,6 @@ const ResearchFormLabel = ({ children, ...props }) => (
</Label>
)

const beforeUnload = (e) => {
e.preventDefault()
e.returnValue = CONFIRM_DIALOG_MSG
}

const ResearchForm = observer((props: IProps) => {
const { formValues, parentType } = props
const { create, update } = buttons.draft
Expand All @@ -85,11 +73,7 @@ const ResearchForm = observer((props: IProps) => {
} = overview

const store = useResearchStore()
const [state, setState] = React.useState<IState>({
formSaved: false,
dirty: false,
showSubmitModal: false,
})
const [showSubmitModal, setShowSubmitModal] = React.useState(false)
const [submissionHandler, setSubmissionHandler] = React.useState({
draft: formValues.moderation === IModerationStatus.DRAFT,
shouldSubmit: false,
Expand All @@ -104,20 +88,14 @@ const ResearchForm = observer((props: IProps) => {
}
}, [store.activeUser])

React.useEffect(() => {
if (store.researchUploadStatus.Complete) {
window.removeEventListener('beforeunload', beforeUnload, false)
}
}, [store.researchUploadStatus.Complete])

React.useEffect(() => {
if (submissionHandler.shouldSubmit) {
const form = document.getElementById('researchForm')
if (typeof form !== 'undefined' && form !== null) {
form.dispatchEvent(
new Event('submit', { cancelable: true, bubbles: true }),
)
setState((prevState) => ({ ...prevState, showSubmitModal: true }))
setShowSubmitModal(true)
}
}
}, [submissionHandler])
Expand All @@ -129,48 +107,30 @@ const ResearchForm = observer((props: IProps) => {
await store.uploadResearch(formValues)
}

// Display a confirmation dialog when leaving the page outside the React Router
const unloadDecorator = (form) => {
return form.subscribe(
({ dirty }) => {
if (dirty && !store.researchUploadStatus.Complete) {
window.addEventListener('beforeunload', beforeUnload, false)
return
}
window.removeEventListener('beforeunload', beforeUnload, false)
},
{ dirty: true },
)
}

const draftButtonText =
formValues.moderation !== IModerationStatus.DRAFT ? create : update
const pageTitle = headings.overview[parentType]

return (
<div data-testid={props['data-testid']}>
{state.showSubmitModal && (
{showSubmitModal && (
<ResearchSubmitStatus
{...props}
onClose={() => {
setState((prevState) => ({ ...prevState, showSubmitModal: false }))
setShowSubmitModal(false)
store.resetResearchUploadStatus()
}}
/>
)}

<Form
onSubmit={(v) => {
onSubmit(v as IResearch.FormInput)
}}
onSubmit={async (v) => await onSubmit(v as IResearch.FormInput)}
initialValues={formValues}
mutators={{
setAllowDraftSaveFalse,
setAllowDraftSaveTrue,
...arrayMutators,
}}
validateOnBlur
decorators={[unloadDecorator]}
render={({
dirty,
errors,
Expand All @@ -179,17 +139,11 @@ const ResearchForm = observer((props: IProps) => {
hasValidationErrors,
submitting,
submitFailed,
submitSucceeded,
}) => {
if (state.dirty !== dirty) {
setState((prev) => ({ ...prev, dirty }))
}

return (
<Flex mx={-2} bg={'inherit'} sx={{ flexWrap: 'wrap' }}>
<UnsavedChangesDialog
uploadComplete={store.updateUploadStatus.Complete}
message={CONFIRM_DIALOG_MSG}
/>
<Flex mx={-2} bg="inherit" sx={{ flexWrap: 'wrap' }}>
<UnsavedChangesDialog hasChanges={dirty && !submitSucceeded} />

<Flex
bg="inherit"
Expand Down
25 changes: 14 additions & 11 deletions src/pages/Research/Content/Common/ResearchUpdate.form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,20 @@ export const ResearchUpdateForm = observer((props: IProps) => {
}, 0)
}

const onSubmit = (formValues: IResearch.Update) => {
const onSubmit = async (formValues: IResearch.Update) => {
setShowSubmitModal(true)
if (formValues.fileLink && formValues.files && formValues.files.length > 0)

if (
formValues.fileLink &&
formValues.files &&
formValues.files.length > 0
) {
return setInvalidFileWarning(true)
else setInvalidFileWarning(false)
}

setInvalidFileWarning(false)

store.uploadUpdate({
await store.uploadUpdate({
...formValues,
collaborators: Array.from(
new Set(
Expand Down Expand Up @@ -159,9 +166,7 @@ export const ResearchUpdateForm = observer((props: IProps) => {
/>
)}
<Form
onSubmit={(v) => {
onSubmit(v as IResearch.Update)
}}
onSubmit={async (v) => await onSubmit(v as IResearch.Update)}
initialValues={formValues}
mutators={{
setAllowDraftSaveFalse,
Expand All @@ -175,6 +180,7 @@ export const ResearchUpdateForm = observer((props: IProps) => {
handleSubmit,
hasValidationErrors,
errors,
submitSucceeded,
submitting,
submitFailed,
values,
Expand All @@ -191,10 +197,7 @@ export const ResearchUpdateForm = observer((props: IProps) => {
sx={{ flexWrap: 'wrap' }}
data-testid="EditResearchUpdate"
>
<UnsavedChangesDialog
uploadComplete={store.updateUploadStatus.Complete}
message={CONFIRM_DIALOG_MSG}
/>
<UnsavedChangesDialog hasChanges={dirty && !submitSucceeded} />
<Flex
bg="inherit"
px={2}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Research/Content/Common/SubmitStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const ResearchSubmitStatus = observer((props: IProps) => {
Uploading Research
</Heading>
<Icon
glyph={'close'}
glyph="close"
onClick={() => {
props.onClose()
}}
Expand Down
Loading

0 comments on commit a387fd8

Please sign in to comment.