-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* refactor output form modal * linting * linting * Update packages/gp2-components/src/organisms/__tests__/ConfirmAndSaveOutput.test.tsx Co-authored-by: Gabriela Ueno <[email protected]> --------- Co-authored-by: Gabriela Ueno <[email protected]>
- Loading branch information
Showing
5 changed files
with
711 additions
and
968 deletions.
There are no files selected for viewing
163 changes: 163 additions & 0 deletions
163
packages/gp2-components/src/organisms/ConfirmAndSaveOutput.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import { ReactNode, useState } from 'react'; | ||
import { ConfirmModal as Modal, Link } from '@asap-hub/react-components'; | ||
import { | ||
INVITE_SUPPORT_EMAIL, | ||
mailToSupport, | ||
} from '@asap-hub/react-components/src/mail'; | ||
import { gp2 } from '@asap-hub/model'; | ||
import { useNotificationContext } from '@asap-hub/react-context'; | ||
|
||
import { EntityMappper } from '../templates/CreateOutputPage'; | ||
import { GetWrappedOnSave } from './Form'; | ||
|
||
const capitalizeFirstLetter = (string: string) => | ||
string.charAt(0).toUpperCase() + string.slice(1); | ||
export type ConfirmAndSaveOutputProps = { | ||
children: (state: { | ||
save: () => Promise<gp2.OutputResponse | void>; | ||
}) => ReactNode; | ||
getWrappedOnSave: GetWrappedOnSave<gp2.OutputResponse>; | ||
setRedirectOnSave: (url: string) => void; | ||
path: (id: string) => string; | ||
documentType: gp2.OutputDocumentType; | ||
title: string | undefined; | ||
currentPayload: gp2.OutputPostRequest; | ||
isEditing: boolean; | ||
createVersion: boolean; | ||
shareOutput: ( | ||
payload: gp2.OutputPostRequest, | ||
) => Promise<gp2.OutputResponse | void>; | ||
entityType: 'workingGroup' | 'project'; | ||
}; | ||
|
||
const getBannerMessage = ( | ||
entityType: 'workingGroup' | 'project', | ||
documentType: gp2.OutputDocumentType, | ||
published: boolean, | ||
createVersion: boolean, | ||
) => | ||
`${createVersion ? 'New ' : ''}${EntityMappper[entityType]} ${documentType} ${ | ||
createVersion ? 'version ' : '' | ||
}${published || createVersion ? 'published' : 'saved'} successfully.`; | ||
|
||
export const ConfirmAndSaveOutput = ({ | ||
children, | ||
getWrappedOnSave, | ||
setRedirectOnSave, | ||
path, | ||
documentType, | ||
title, | ||
shareOutput, | ||
currentPayload, | ||
createVersion, | ||
isEditing, | ||
entityType, | ||
}: ConfirmAndSaveOutputProps) => { | ||
const [displayPublishModal, setDisplayPublishModal] = useState(false); | ||
const [displayVersionModal, setDiplayVersionModal] = useState(false); | ||
|
||
const { addNotification, removeNotification, notifications } = | ||
useNotificationContext(); | ||
|
||
const setBannerMessage = ( | ||
message: string, | ||
page: 'output' | 'output-form', | ||
bannerType: 'error' | 'success', | ||
) => { | ||
if ( | ||
notifications[0] && | ||
notifications[0]?.message !== capitalizeFirstLetter(message) | ||
) { | ||
removeNotification(notifications[0]); | ||
} | ||
addNotification({ | ||
message: capitalizeFirstLetter(message), | ||
page, | ||
type: bannerType, | ||
}); | ||
}; | ||
const save = async (skipConfirmationModal: boolean = false) => { | ||
const displayModalFn = | ||
!isEditing && !skipConfirmationModal | ||
? () => { | ||
setDisplayPublishModal(true); | ||
} | ||
: createVersion && !skipConfirmationModal | ||
? () => { | ||
setDiplayVersionModal(true); | ||
} | ||
: null; | ||
|
||
const output = await getWrappedOnSave( | ||
() => shareOutput(currentPayload), | ||
(error) => setBannerMessage(error, 'output-form', 'error'), | ||
displayModalFn, | ||
)(); | ||
|
||
if (output && typeof output.id === 'string') { | ||
setBannerMessage( | ||
getBannerMessage(entityType, documentType, !title, createVersion), | ||
'output', | ||
'success', | ||
); | ||
setRedirectOnSave(path(output.id)); | ||
} | ||
return output; | ||
}; | ||
return ( | ||
<> | ||
{displayPublishModal && ( | ||
<Modal | ||
title="Publish output for the whole hub?" | ||
cancelText="Cancel" | ||
onCancel={() => setDisplayPublishModal(false)} | ||
confirmText="Publish Output" | ||
onSave={async () => { | ||
const skipPublishModal = true; | ||
const result = await save(skipPublishModal); | ||
if (!result) { | ||
setDisplayPublishModal(false); | ||
} | ||
}} | ||
description={ | ||
<> | ||
All {entityType === 'workingGroup' ? 'working group' : 'project'}{' '} | ||
members listed on this output will be notified and all GP2 members | ||
will be able to access it. If you need to unpublish this output, | ||
please contact{' '} | ||
{<Link href={mailToSupport()}>{INVITE_SUPPORT_EMAIL}</Link>}. | ||
</> | ||
} | ||
/> | ||
)} | ||
|
||
{displayVersionModal && ( | ||
<Modal | ||
title="Publish new version for the whole hub?" | ||
cancelText="Cancel" | ||
onCancel={() => setDiplayVersionModal(false)} | ||
confirmText="Publish new version" | ||
onSave={async () => { | ||
const skipPublishModal = true; | ||
const result = await save(skipPublishModal); | ||
if (!result) { | ||
setDiplayVersionModal(false); | ||
} | ||
}} | ||
description={ | ||
<> | ||
All working group members listed on this output will be notified | ||
and all GP2 members will be able to access it. If you want to add | ||
or edit older versions after this new version was published, | ||
please contact{' '} | ||
{<Link href={mailToSupport()}>{INVITE_SUPPORT_EMAIL}</Link>}. | ||
</> | ||
} | ||
/> | ||
)} | ||
{children({ | ||
save, | ||
})} | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
151 changes: 151 additions & 0 deletions
151
packages/gp2-components/src/organisms/__tests__/ConfirmAndSaveOutput.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import { createOutputResponse } from '@asap-hub/fixtures/src/gp2'; | ||
import { OutputResponse } from '@asap-hub/model/src/gp2'; | ||
import { Button } from '@asap-hub/react-components'; | ||
import { NotificationContext } from '@asap-hub/react-context'; | ||
import { render, screen, waitFor, within } from '@testing-library/react'; | ||
import userEvent from '@testing-library/user-event'; | ||
import { createMemoryHistory } from 'history'; | ||
import { Router } from 'react-router-dom'; | ||
|
||
import { | ||
ConfirmAndSaveOutput, | ||
ConfirmAndSaveOutputProps, | ||
} from '../ConfirmAndSaveOutput'; | ||
import Form, { GetWrappedOnSave } from '../Form'; | ||
|
||
describe('ConfirmAndSaveOutput', () => { | ||
const addNotification = jest.fn(); | ||
const history = createMemoryHistory(); | ||
const shareOutput = jest.fn(); | ||
|
||
const wrapper: React.ComponentType = ({ children }) => ( | ||
<NotificationContext.Provider | ||
value={{ | ||
notifications: [], | ||
addNotification, | ||
removeNotification: jest.fn(), | ||
}} | ||
> | ||
<Router history={history}>{children}</Router> | ||
</NotificationContext.Provider> | ||
); | ||
|
||
const renderElement = (props?: Partial<ConfirmAndSaveOutputProps>) => | ||
render( | ||
<Form dirty={false}> | ||
{({ getWrappedOnSave }) => ( | ||
<ConfirmAndSaveOutput | ||
path={(id: string) => id} | ||
documentType="Article" | ||
title="title" | ||
currentPayload={{ | ||
...createOutputResponse(), | ||
tagIds: [], | ||
contributingCohortIds: [], | ||
mainEntityId: '', | ||
relatedOutputIds: [], | ||
relatedEventIds: [], | ||
authors: [], | ||
}} | ||
shareOutput={shareOutput} | ||
setRedirectOnSave={(url: string) => {}} | ||
entityType="project" | ||
isEditing={false} | ||
createVersion={false} | ||
getWrappedOnSave={ | ||
getWrappedOnSave as unknown as GetWrappedOnSave<OutputResponse> | ||
} | ||
{...props} | ||
> | ||
{({ save }) => <Button onClick={save}>Publish</Button>} | ||
</ConfirmAndSaveOutput> | ||
)} | ||
</Form>, | ||
{ wrapper }, | ||
); | ||
|
||
describe('cancel', () => { | ||
it('closes the publish modal when user clicks on cancel', async () => { | ||
renderElement(); | ||
userEvent.click(screen.getByRole('button', { name: 'Publish' })); | ||
|
||
expect( | ||
screen.getByText('Publish output for the whole hub?'), | ||
).toBeVisible(); | ||
|
||
userEvent.click( | ||
within(screen.getByRole('dialog')).getByRole('button', { | ||
name: 'Cancel', | ||
}), | ||
); | ||
|
||
await waitFor(() => { | ||
expect( | ||
screen.queryByText('Publish output for the whole hub?'), | ||
).not.toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
it('closes the version modal when user clicks on cancel', async () => { | ||
renderElement({ isEditing: true, createVersion: true }); | ||
|
||
userEvent.click(screen.getByRole('button', { name: 'Publish' })); | ||
|
||
expect( | ||
screen.getByText('Publish new version for the whole hub?'), | ||
).toBeVisible(); | ||
|
||
userEvent.click( | ||
within(screen.getByRole('dialog')).getByRole('button', { | ||
name: 'Cancel', | ||
}), | ||
); | ||
|
||
await waitFor(() => { | ||
expect( | ||
screen.queryByText('Publish new version for the whole hub?'), | ||
).not.toBeInTheDocument(); | ||
}); | ||
}); | ||
}); | ||
describe('server side errors', () => { | ||
it('closes the publish modal when user clicks on save and there are server side errors', async () => { | ||
shareOutput.mockRejectedValueOnce(new Error('something went wrong')); | ||
renderElement(); | ||
|
||
userEvent.click(screen.getByRole('button', { name: 'Publish' })); | ||
|
||
expect( | ||
screen.getByText('Publish output for the whole hub?'), | ||
).toBeVisible(); | ||
|
||
userEvent.click(screen.getByRole('button', { name: /Publish output/i })); | ||
|
||
await waitFor(() => { | ||
expect( | ||
screen.queryByText('Publish output for the whole hub?'), | ||
).not.toBeInTheDocument(); | ||
}); | ||
}); | ||
it('closes the version modal when user clicks on save and there are server side errors', async () => { | ||
shareOutput.mockRejectedValueOnce(new Error('something went wrong')); | ||
renderElement({ isEditing: true, createVersion: true }); | ||
|
||
userEvent.click(screen.getByRole('button', { name: 'Publish' })); | ||
|
||
expect( | ||
screen.getByText('Publish new version for the whole hub?'), | ||
).toBeVisible(); | ||
|
||
userEvent.click( | ||
screen.getByRole('button', { name: /Publish new version/i }), | ||
); | ||
|
||
await waitFor(() => { | ||
expect( | ||
screen.queryByText('Publish new version for the whole hub?'), | ||
).not.toBeInTheDocument(); | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.