Skip to content

Commit

Permalink
ASAP-446 Add manuscript (#4274)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabiayako authored May 16, 2024
1 parent 243eb64 commit 1b28a2c
Show file tree
Hide file tree
Showing 50 changed files with 1,810 additions and 77 deletions.
31 changes: 31 additions & 0 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
1 change: 1 addition & 0 deletions apps/crn-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"react-app-polyfill": "3.0.0",
"react-dom": "17.0.2",
"react-error-boundary": "3.1.4",
"react-hook-form": "^7.51.4",
"react-router-dom": "5.3.4",
"react-router-last-location": "2.0.1",
"recoil": "0.7.7",
Expand Down
34 changes: 34 additions & 0 deletions apps/crn-frontend/src/network/teams/ManuscriptToastProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Toast } from '@asap-hub/react-components';
import React, { createContext, useState } from 'react';

type ManuscriptToastContextData = {
setShowSuccessBanner: React.Dispatch<React.SetStateAction<boolean>>;
};

export const ManuscriptToastContext = createContext<ManuscriptToastContextData>(
{} as ManuscriptToastContextData,
);

export const ManuscriptToastProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
const [showSuccessBanner, setShowSuccessBanner] = useState<boolean>(false);

return (
<ManuscriptToastContext.Provider value={{ setShowSuccessBanner }}>
<>
{showSuccessBanner && (
<Toast
accent="successLarge"
onClose={() => setShowSuccessBanner(false)}
>
Manuscript submitted successfully.
</Toast>
)}
{children}
</>
</ManuscriptToastContext.Provider>
);
};
38 changes: 38 additions & 0 deletions apps/crn-frontend/src/network/teams/TeamManuscript.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Frame } from '@asap-hub/frontend-utils';
import {
ManuscriptForm,
ManuscriptHeader,
usePushFromHere,
} from '@asap-hub/react-components';
import { network } from '@asap-hub/routing';
import { FormProvider, useForm } from 'react-hook-form';
import { usePostManuscript } from './state';
import { useManuscriptToast } from './useManuscriptToast';

type TeamManuscriptProps = {
teamId: string;
};
const TeamManuscript: React.FC<TeamManuscriptProps> = ({ teamId }) => {
const { setShowSuccessBanner } = useManuscriptToast();
const form = useForm();
const createManuscript = usePostManuscript();

const pushFromHere = usePushFromHere();

const onSuccess = () => {
const path = network({}).teams({}).team({ teamId }).workspace({}).$;

setShowSuccessBanner(true);
pushFromHere(path);
};

return (
<FormProvider {...form}>
<Frame title="Create Manuscript">
<ManuscriptHeader />
<ManuscriptForm onSuccess={onSuccess} onSave={createManuscript} />
</Frame>
</FormProvider>
);
};
export default TeamManuscript;
113 changes: 62 additions & 51 deletions apps/crn-frontend/src/network/teams/TeamProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import {
import { useUpcomingAndPastEvents } from '../events';
import ProfileSwitch from '../ProfileSwitch';

import { ManuscriptToastProvider } from './ManuscriptToastProvider';
import { useTeamById } from './state';
import TeamManuscript from './TeamManuscript';

const loadAbout = () =>
import(/* webpackChunkName: "network-team-about" */ './About');
Expand Down Expand Up @@ -134,60 +136,69 @@ const TeamProfile: FC<TeamProfileProps> = ({ currentTime }) => {
<ResearchOutputPermissionsContext.Provider
value={{ canShareResearchOutput, canDuplicateResearchOutput }}
>
<Switch>
{canShareResearchOutput && (
<Route path={path + createOutput.template}>
<Frame title="Share Output">
<TeamOutput teamId={teamId} />
<ManuscriptToastProvider>
<Switch>
<Route
path={workspace({}).$ + workspace({}).createManuscript.template}
>
<Frame title="Create Manuscript">
<TeamManuscript teamId={teamId} />
</Frame>
</Route>
)}
{canDuplicateResearchOutput && (
<Route path={path + duplicateOutput.template}>
<Frame title="Duplicate Output">
<DuplicateOutput />
</Frame>
</Route>
)}
<TeamProfilePage
{...team}
teamListElementId={teamListElementId}
upcomingEventsCount={upcomingEvents?.total || 0}
pastEventsCount={pastEvents?.total || 0}
teamOutputsCount={teamOutputsResult.total}
teamDraftOutputsCount={
canShareResearchOutput ? outputDraftResults.total : undefined
}
>
<ProfileSwitch
About={() => (
<About teamListElementId={teamListElementId} team={team} />
)}
currentTime={currentTime}
displayName={team.displayName}
eventConstraint={{ teamId }}
isActive={!team?.inactiveSince}
Outputs={
<Outputs
userAssociationMember={canShareResearchOutput}
team={team}
/>
}
DraftOutputs={
<Outputs
team={team}
draftOutputs
userAssociationMember={canShareResearchOutput}
/>
{canShareResearchOutput && (
<Route path={path + createOutput.template}>
<Frame title="Share Output">
<TeamOutput teamId={teamId} />
</Frame>
</Route>
)}
{canDuplicateResearchOutput && (
<Route path={path + duplicateOutput.template}>
<Frame title="Duplicate Output">
<DuplicateOutput />
</Frame>
</Route>
)}
<TeamProfilePage
{...team}
teamListElementId={teamListElementId}
upcomingEventsCount={upcomingEvents?.total || 0}
pastEventsCount={pastEvents?.total || 0}
teamOutputsCount={teamOutputsResult.total}
teamDraftOutputsCount={
canShareResearchOutput ? outputDraftResults.total : undefined
}
paths={paths}
type="team"
Workspace={() => (
<Workspace team={{ ...team, tools: team.tools ?? [] }} />
)}
/>
</TeamProfilePage>
</Switch>
>
<ProfileSwitch
About={() => (
<About teamListElementId={teamListElementId} team={team} />
)}
currentTime={currentTime}
displayName={team.displayName}
eventConstraint={{ teamId }}
isActive={!team?.inactiveSince}
Outputs={
<Outputs
userAssociationMember={canShareResearchOutput}
team={team}
/>
}
DraftOutputs={
<Outputs
team={team}
draftOutputs
userAssociationMember={canShareResearchOutput}
/>
}
paths={paths}
type="team"
Workspace={() => (
<Workspace team={{ ...team, tools: team.tools ?? [] }} />
)}
/>
</TeamProfilePage>
</Switch>
</ManuscriptToastProvider>
</ResearchOutputPermissionsContext.Provider>
);
}
Expand Down
104 changes: 104 additions & 0 deletions apps/crn-frontend/src/network/teams/__tests__/TeamManuscript.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import {
Auth0Provider,
WhenReady,
} from '@asap-hub/crn-frontend/src/auth/test-utils';
import { network } from '@asap-hub/routing';
import {
render,
screen,
waitFor,
waitForElementToBeRemoved,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { createMemoryHistory } from 'history';
import { ComponentProps, Suspense } from 'react';
import { Route, Router } from 'react-router-dom';
import { RecoilRoot } from 'recoil';

import { createManuscript } from '../api';
import { ManuscriptToastProvider } from '../ManuscriptToastProvider';
import { refreshTeamState } from '../state';
import TeamManuscript from '../TeamManuscript';

const manuscriptResponse = { id: '1', title: 'The Manuscript' };

const teamId = '42';
const history = createMemoryHistory({
initialEntries: [
network({}).teams({}).team({ teamId }).workspace({}).createManuscript({}).$,
],
});
jest.mock('../api', () => ({
createManuscript: jest.fn().mockResolvedValue(manuscriptResponse),
}));

beforeEach(() => {
jest.resetModules();
});

const renderPage = async (
user: ComponentProps<typeof Auth0Provider>['user'] = {},
) => {
const path =
network.template +
network({}).teams.template +
network({}).teams({}).team.template +
network({}).teams({}).team({ teamId }).workspace.template +
network({}).teams({}).team({ teamId }).workspace({}).createManuscript
.template;

const { container } = render(
<RecoilRoot
initializeState={({ set }) => {
set(refreshTeamState(teamId), Math.random());
}}
>
<Suspense fallback="loading">
<Auth0Provider user={user}>
<WhenReady>
<Router history={history}>
<Route path={path}>
<ManuscriptToastProvider>
<TeamManuscript teamId={teamId} />
</ManuscriptToastProvider>
</Route>
</Router>
</WhenReady>
</Auth0Provider>
</Suspense>
</RecoilRoot>,
);
await waitForElementToBeRemoved(() => screen.queryByText(/loading/i));
return { container };
};

it('renders manuscript form page', async () => {
const { container } = await renderPage();

expect(container).toHaveTextContent(
'Submit your manuscript to receive a compliance report and find out which areas need to be improved before publishing your article',
);
expect(container).toHaveTextContent('What are you sharing');
expect(container).toHaveTextContent('Title of Manuscript');
});

it('can publish a form when the data is valid and navigates to team workspace', async () => {
const title = 'The Manuscript';

await renderPage();

userEvent.type(
screen.getByRole('textbox', { name: /title of manuscript/i }),
title,
);

const submitButton = screen.getByRole('button', { name: /Submit/i });
userEvent.click(submitButton);

await waitFor(() => {
expect(createManuscript).toHaveBeenCalledWith({ title }, expect.anything());
expect(history.location.pathname).toBe(
`/network/teams/${teamId}/workspace`,
);
});
});
Loading

0 comments on commit 1b28a2c

Please sign in to comment.