Skip to content

Commit

Permalink
ASAP-531 Edit Manuscript (#4430)
Browse files Browse the repository at this point in the history
* ASAP-531 Edit Manuscript

* fix rebase issue
  • Loading branch information
gabiayako authored Nov 5, 2024
1 parent 48d8e44 commit 8e6cc2f
Show file tree
Hide file tree
Showing 35 changed files with 2,792 additions and 495 deletions.
63 changes: 59 additions & 4 deletions apps/crn-frontend/src/network/teams/TeamManuscript.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Frame } from '@asap-hub/frontend-utils';
import { AuthorResponse, AuthorSelectOption } from '@asap-hub/model';
import {
ManuscriptForm,
ManuscriptHeader,
usePushFromHere,
} from '@asap-hub/react-components';
import { network } from '@asap-hub/routing';
import { network, useRouteParams } from '@asap-hub/routing';
import { FormProvider, useForm } from 'react-hook-form';
import { useSetRecoilState } from 'recoil';
import {
Expand All @@ -14,25 +15,39 @@ import {
} from '../../shared-state';
import {
refreshTeamState,
useManuscriptById,
usePostManuscript,
usePutManuscript,
useTeamById,
useUploadManuscriptFile,
} from './state';
import { useEligibilityReason } from './useEligibilityReason';
import { useManuscriptToast } from './useManuscriptToast';

const useParamManuscriptVersion = (teamId: string): string => {
const route = network({})
.teams({})
.team({ teamId })
.workspace({}).editManuscript;
const { manuscriptId } = useRouteParams(route);
return manuscriptId;
};

type TeamManuscriptProps = {
teamId: string;
};
const TeamManuscript: React.FC<TeamManuscriptProps> = ({ teamId }) => {
const setRefreshTeamState = useSetRecoilState(refreshTeamState(teamId));
const manuscriptId = useParamManuscriptVersion(teamId);
const manuscript = useManuscriptById(manuscriptId);

const team = useTeamById(teamId);

const { eligibilityReasons } = useEligibilityReason();
const { setFormType } = useManuscriptToast();
const form = useForm();
const createManuscript = usePostManuscript();
const updateManuscript = usePutManuscript();
const handleFileUpload = useUploadManuscriptFile();
const getTeamSuggestions = useTeamSuggestions();
const getLabSuggestions = useLabSuggestions();
Expand All @@ -47,27 +62,57 @@ const TeamManuscript: React.FC<TeamManuscriptProps> = ({ teamId }) => {
pushFromHere(path);
};

const selectedTeams = [
const {
teams: manuscriptTeams,
labs: manuscriptLabs,
firstAuthors: manuscriptFirstAuthors,
correspondingAuthor: manuscriptCorrespondingAuthor,
additionalAuthors: manuscriptAdditionalAuthors,
...manuscriptVersion
} = manuscript?.versions[0] || {};
const selectedTeams = manuscriptTeams?.map((selectedTeam, index) => ({
value: selectedTeam.id,
label: selectedTeam.displayName,
isFixed: index === 0,
})) || [
{
label: team?.displayName || '',
value: teamId,
label: team?.displayName || '',
isFixed: true,
},
];

const selectedLabs = (manuscriptLabs || []).map((lab) => ({
value: lab.id,
label: lab.name,
isFixed: false,
}));

const convertAuthorsToSelectOptions = (
authors: AuthorResponse[] | undefined,
) =>
(authors || []).map((author) => ({
author,
label: author.displayName,
value: author.id,
})) as (AuthorResponse & AuthorSelectOption)[];

return (
<FormProvider {...form}>
<Frame title="Create Manuscript">
<ManuscriptHeader />
<ManuscriptForm
manuscriptId={manuscriptId}
onSuccess={onSuccess}
onSave={createManuscript}
onCreate={createManuscript}
onUpdate={updateManuscript}
teamId={teamId}
handleFileUpload={handleFileUpload}
eligibilityReasons={eligibilityReasons}
getTeamSuggestions={getTeamSuggestions}
selectedTeams={selectedTeams}
getLabSuggestions={getLabSuggestions}
selectedLabs={selectedLabs}
getAuthorSuggestions={(input) =>
getAuthorSuggestions(input).then((authors) =>
authors.map((author) => ({
Expand All @@ -77,9 +122,19 @@ const TeamManuscript: React.FC<TeamManuscriptProps> = ({ teamId }) => {
})),
)
}
title={manuscript?.title}
firstAuthors={convertAuthorsToSelectOptions(manuscriptFirstAuthors)}
correspondingAuthor={convertAuthorsToSelectOptions(
manuscriptCorrespondingAuthor,
)}
additionalAuthors={convertAuthorsToSelectOptions(
manuscriptAdditionalAuthors,
)}
{...manuscriptVersion}
/>
</Frame>
</FormProvider>
);
};

export default TeamManuscript;
7 changes: 7 additions & 0 deletions apps/crn-frontend/src/network/teams/TeamProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,13 @@ const TeamProfile: FC<TeamProfileProps> = ({ currentTime }) => {
<TeamManuscript teamId={teamId} />
</Frame>
</Route>
<Route
path={workspace({}).$ + workspace({}).editManuscript.template}
>
<Frame title="Edit Manuscript">
<TeamManuscript teamId={teamId} />
</Frame>
</Route>
{canCreateComplianceReport && (
<Route
path={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ jest.mock('../../users/api');

jest.mock('../api', () => ({
createManuscript: jest.fn().mockResolvedValue(manuscriptResponse),
getManuscript: jest.fn().mockResolvedValue(null),
uploadManuscriptFile: jest.fn().mockResolvedValue({
filename: 'manuscript.pdf',
url: 'https://example.com/manuscript.pdf',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ it('displays manuscript success toast message and user can dismiss toast', async
expect(await screen.findByText(/tools/i)).toBeVisible();

userEvent.click(screen.getByText(/Submit Manuscript/i));

userEvent.click(screen.getByText(/Yes/i));

userEvent.click(
Expand All @@ -203,6 +204,10 @@ it('displays manuscript success toast message and user can dismiss toast', async
);
userEvent.click(screen.getByText(/Continue/i));

await waitFor(() =>
expect(screen.queryByText(/loading/i)).not.toBeInTheDocument(),
);

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

await waitFor(() => {
Expand Down
50 changes: 26 additions & 24 deletions apps/crn-frontend/src/network/teams/__tests__/Workspace.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -372,20 +372,21 @@ describe('manuscript quick check discussion', () => {
enable('DISPLAY_MANUSCRIPTS');

mockGetDiscussion.mockResolvedValueOnce(acknowledgedGrantNumberDiscussion);
const { getByText, findByTestId, getByTestId } = renderWithWrapper(
<Workspace
team={{
...createTeamResponse(),
id,
manuscripts: [manuscript],
tools: [],
}}
/>,
);
const { getByText, findByTestId, getByLabelText, getByTestId } =
renderWithWrapper(
<Workspace
team={{
...createTeamResponse(),
id,
manuscripts: [manuscript],
tools: [],
}}
/>,
);

await act(async () => {
userEvent.click(await findByTestId('collapsible-button'));
userEvent.click(getByTestId('version-collapsible-button'));
userEvent.click(getByLabelText('Expand Version'));
});

userEvent.click(getByTestId('discussion-collapsible-button'));
Expand All @@ -402,22 +403,23 @@ describe('manuscript quick check discussion', () => {
enable('DISPLAY_MANUSCRIPTS');
mockGetDiscussion.mockResolvedValue(acknowledgedGrantNumberDiscussion);
mockUpdateDiscussion.mockResolvedValue(acknowledgedGrantNumberDiscussion);
const { findByTestId, getByRole, getByTestId } = renderWithWrapper(
<ManuscriptToastProvider>
<Workspace
team={{
...createTeamResponse(),
id,
manuscripts: [manuscript],
tools: [],
}}
/>
</ManuscriptToastProvider>,
);
const { findByTestId, getByRole, getByTestId, getByLabelText } =
renderWithWrapper(
<ManuscriptToastProvider>
<Workspace
team={{
...createTeamResponse(),
id,
manuscripts: [manuscript],
tools: [],
}}
/>
</ManuscriptToastProvider>,
);

await act(async () => {
userEvent.click(await findByTestId('collapsible-button'));
userEvent.click(getByTestId('version-collapsible-button'));
userEvent.click(getByLabelText('Expand Version'));
});

userEvent.click(getByTestId('discussion-collapsible-button'));
Expand Down
13 changes: 12 additions & 1 deletion apps/crn-frontend/src/network/teams/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
DiscussionResponse,
} from '@asap-hub/model';
import { useCurrentUserCRN } from '@asap-hub/react-context';
import { useCallback } from 'react';
import {
atom,
atomFamily,
Expand Down Expand Up @@ -186,6 +187,14 @@ export const manuscriptState = atomFamily<
default: fetchManuscriptState,
});

export const useInvalidateManuscriptIndex = () => {
const [refresh, setRefresh] = useRecoilState(refreshManuscriptIndex);

return useCallback(() => {
setRefresh(refresh + 1);
}, [refresh, setRefresh]);
};

export const useManuscriptById = (id: string) =>
useRecoilValue(manuscriptState(id));

Expand All @@ -210,10 +219,12 @@ export const usePostManuscript = () => {
export const usePutManuscript = () => {
const authorization = useRecoilValue(authorizationState);
const setManuscriptItem = useSetManuscriptItem();
const invalidateManuscriptIndex = useInvalidateManuscriptIndex();

return async (id: string, payload: ManuscriptPutRequest) => {
const manuscript = await updateManuscript(id, payload, authorization);
setManuscriptItem(manuscript);

invalidateManuscriptIndex();
return manuscript;
};
};
Expand Down
49 changes: 46 additions & 3 deletions apps/crn-server/src/controllers/manuscript.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import {
ManuscriptFileResponse,
ManuscriptFileType,
ManuscriptPostAuthor,
ManuscriptPutRequest,
ManuscriptResponse,
ManuscriptUpdateDataObject,
} from '@asap-hub/model';

import {
Expand Down Expand Up @@ -138,15 +138,58 @@ export default class ManuscriptController {

async update(
id: string,
manuscriptData: ManuscriptUpdateDataObject,
manuscriptData: ManuscriptPutRequest,
userId: string,
): Promise<ManuscriptResponse> {
const currentManuscript = await this.manuscriptDataProvider.fetchById(id);

if (!currentManuscript) {
throw new NotFoundError(undefined, `manuscript with id ${id} not found`);
}

await this.manuscriptDataProvider.update(id, manuscriptData);
if ('status' in manuscriptData && manuscriptData.status) {
await this.manuscriptDataProvider.update(id, manuscriptData, userId);
return this.fetchById(id);
}

if ('versions' in manuscriptData && manuscriptData.versions?.[0]) {
const {
firstAuthors,
correspondingAuthor,
additionalAuthors,
...versionData
} = manuscriptData.versions[0];

const firstAuthorsValues = await this.mapAuthorsPostRequestToId(
firstAuthors ?? [],
);
const correspondingAuthorValues = correspondingAuthor
? await this.mapAuthorsPostRequestToId([correspondingAuthor] ?? [])
: [];

const additionalAuthorsValues = await this.mapAuthorsPostRequestToId(
additionalAuthors ?? [],
);

const getValidAuthorIds = (authorIds: (string | null)[]) =>
authorIds.filter((authorId): authorId is string => authorId !== null);

await this.manuscriptDataProvider.update(
id,
{
...manuscriptData,
versions: [
{
...versionData,
firstAuthors: getValidAuthorIds(firstAuthorsValues),
correspondingAuthor: getValidAuthorIds(correspondingAuthorValues),
additionalAuthors: getValidAuthorIds(additionalAuthorsValues),
},
],
},
userId,
);
}

return this.fetchById(id);
}
Expand Down
Loading

0 comments on commit 8e6cc2f

Please sign in to comment.