From 7cf0e92dd1e8e853d2bd04d720ae0f109dd8c0d7 Mon Sep 17 00:00:00 2001 From: Jarkko Pesonen <435495+jrkkp@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:56:07 +0200 Subject: [PATCH] VKT(Frontend & Backend): Enrollment appointment clerk interface --- .../api/clerk/ClerkEnrollmentController.java | 2 +- .../oph/vkt/model/EnrollmentAppointment.java | 6 ++++ .../vkt/service/ClerkEnrollmentService.java | 4 +++ .../fi/oph/vkt/util/ClerkEnrollmentUtil.java | 6 ++-- .../db/changelog/db.changelog-1.0.xml | 6 ++++ .../ClerkEnrollmentContactRequestPage.tsx | 29 +++++++++++++++++-- .../reducers/clerkEnrollmentContactRequest.ts | 12 ++++++++ .../sagas/clerkEnrollmentContactRequest.ts | 27 +++++++++++++++++ 8 files changed, 86 insertions(+), 6 deletions(-) diff --git a/backend/vkt/src/main/java/fi/oph/vkt/api/clerk/ClerkEnrollmentController.java b/backend/vkt/src/main/java/fi/oph/vkt/api/clerk/ClerkEnrollmentController.java index af482d4f1..4fec6bd38 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/api/clerk/ClerkEnrollmentController.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/api/clerk/ClerkEnrollmentController.java @@ -84,7 +84,7 @@ public ClerkEnrollmentContactRequestDTO getEnrollmentContactRequest(@PathVariabl return clerkEnrollmentService.getEnrollmentContactRequest(enrollmentContactId); } - @PutMapping(path = "/contact/{enrollmentContactId:\\d+}/convertToAppointment") + @PostMapping(path = "/contact/{enrollmentContactId:\\d+}/convertToAppointment", consumes = ALL_VALUE) @Operation(tags = TAG_ENROLLMENT, summary = "Get enrollment contact request") public ClerkEnrollmentAppointmentDTO enrollmentContactRequestToAppointment( @PathVariable final long enrollmentContactId diff --git a/backend/vkt/src/main/java/fi/oph/vkt/model/EnrollmentAppointment.java b/backend/vkt/src/main/java/fi/oph/vkt/model/EnrollmentAppointment.java index 0cca97896..78a5c1aa9 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/model/EnrollmentAppointment.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/model/EnrollmentAppointment.java @@ -58,6 +58,12 @@ public class EnrollmentAppointment extends EnrollmentCommon { @Column(name = "country") private String country; + @Column(name = "first_name") + private String firstName; + + @Column(name = "last_name") + private String lastName; + @Size(max = 255) @Column(name = "auth_hash", unique = true) private String authHash; diff --git a/backend/vkt/src/main/java/fi/oph/vkt/service/ClerkEnrollmentService.java b/backend/vkt/src/main/java/fi/oph/vkt/service/ClerkEnrollmentService.java index 2dfc3fa3c..e468df2f1 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/service/ClerkEnrollmentService.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/service/ClerkEnrollmentService.java @@ -227,6 +227,7 @@ public void getAndSaveKoskiEducationDetailsForEnrollment(final long enrollmentId koskiService.saveEducationsForEnrollment(freeEnrollment, enrollment.getExamEvent().getId(), educationDTOs); } + @Transactional(readOnly = true) public ClerkEnrollmentContactRequestDTO getEnrollmentContactRequest(final long enrollmentContactId) { final EnrollmentAppointment enrollmentAppointment = enrollmentAppointmentRepository.getReferenceById( enrollmentContactId @@ -235,6 +236,7 @@ public ClerkEnrollmentContactRequestDTO getEnrollmentContactRequest(final long e return ClerkEnrollmentUtil.createClerkEnrollmentContactDTO(enrollmentAppointment); } + @Transactional public ClerkEnrollmentAppointmentDTO convertToAppointment(final long enrollmentContactId) { final EnrollmentAppointment enrollmentAppointment = enrollmentAppointmentRepository.getReferenceById( enrollmentContactId @@ -246,6 +248,7 @@ public ClerkEnrollmentAppointmentDTO convertToAppointment(final long enrollmentC return ClerkEnrollmentUtil.createClerkEnrollmentAppointmentDTO(enrollmentAppointment); } + @Transactional(readOnly = true) public ClerkEnrollmentAppointmentDTO getEnrollmentAppointment(final long enrollmentAppointmentId) { final EnrollmentAppointment enrollmentAppointment = enrollmentAppointmentRepository.getReferenceById( enrollmentAppointmentId @@ -254,6 +257,7 @@ public ClerkEnrollmentAppointmentDTO getEnrollmentAppointment(final long enrollm return ClerkEnrollmentUtil.createClerkEnrollmentAppointmentDTO(enrollmentAppointment); } + @Transactional public ClerkEnrollmentAppointmentDTO updateAppointment(final ClerkEnrollmentAppointmentUpdateDTO dto) { final EnrollmentAppointment enrollmentAppointment = enrollmentAppointmentRepository.getReferenceById(dto.id()); diff --git a/backend/vkt/src/main/java/fi/oph/vkt/util/ClerkEnrollmentUtil.java b/backend/vkt/src/main/java/fi/oph/vkt/util/ClerkEnrollmentUtil.java index 30915bfe7..550d493c8 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/util/ClerkEnrollmentUtil.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/util/ClerkEnrollmentUtil.java @@ -172,8 +172,8 @@ public static ClerkEnrollmentAppointmentDTO createClerkEnrollmentAppointmentDTO( .readingComprehensionPartialExam(enrollmentAppointment.isReadingComprehensionPartialExam()) .status(enrollmentAppointment.getStatus()) .email(enrollmentAppointment.getEmail()) - .firstName(enrollmentAppointment.getPerson().getFirstName()) - .lastName(enrollmentAppointment.getPerson().getLastName()) + .firstName(enrollmentAppointment.getFirstName()) + .lastName(enrollmentAppointment.getLastName()) .payments(paymentDTOs) .build(); } @@ -195,6 +195,8 @@ public static ClerkEnrollmentContactRequestDTO createClerkEnrollmentContactDTO( .readingComprehensionPartialExam(enrollmentAppointment.isReadingComprehensionPartialExam()) .status(enrollmentAppointment.getStatus()) .email(enrollmentAppointment.getEmail()) + .firstName(enrollmentAppointment.getFirstName()) + .lastName(enrollmentAppointment.getLastName()) .build(); } } diff --git a/backend/vkt/src/main/resources/db/changelog/db.changelog-1.0.xml b/backend/vkt/src/main/resources/db/changelog/db.changelog-1.0.xml index 642c4637f..b175dfc21 100644 --- a/backend/vkt/src/main/resources/db/changelog/db.changelog-1.0.xml +++ b/backend/vkt/src/main/resources/db/changelog/db.changelog-1.0.xml @@ -918,4 +918,10 @@ + + + + + + diff --git a/frontend/packages/vkt/src/pages/ClerkEnrollmentContactRequestPage.tsx b/frontend/packages/vkt/src/pages/ClerkEnrollmentContactRequestPage.tsx index 7b906f1b5..d7cfd449e 100644 --- a/frontend/packages/vkt/src/pages/ClerkEnrollmentContactRequestPage.tsx +++ b/frontend/packages/vkt/src/pages/ClerkEnrollmentContactRequestPage.tsx @@ -1,7 +1,7 @@ import { ArrowBackIosOutlined as ArrowBackIosOutlinedIcon } from '@mui/icons-material'; import { Box, Divider, Grid, Paper } from '@mui/material'; import { FC, useEffect } from 'react'; -import { useParams } from 'react-router'; +import { useNavigate, useParams } from 'react-router'; import { CustomButton, CustomButtonLink, @@ -16,7 +16,10 @@ import { APIResponseStatus, Color, Variant } from 'shared/enums'; import { useCommonTranslation } from 'configs/i18n'; import { useAppDispatch, useAppSelector } from 'configs/redux'; import { AppRoutes } from 'enums/app'; -import { loadClerkEnrollmentContactRequest } from 'redux/reducers/clerkEnrollmentContactRequest'; +import { + createClerkEnrollmentAppointment, + loadClerkEnrollmentContactRequest, +} from 'redux/reducers/clerkEnrollmentContactRequest'; import { clerkEnrollmentContactRequestSelector } from 'redux/selectors/clerkEnrollmentContactRequest'; const BackButton = () => { @@ -36,11 +39,12 @@ const BackButton = () => { }; export const ClerkEnrollmentContactRequestPage: FC = () => { - const { status, enrollment } = useAppSelector( + const { status, createStatus, enrollment } = useAppSelector( clerkEnrollmentContactRequestSelector, ); const translateCommon = useCommonTranslation(); const params = useParams(); + const navigate = useNavigate(); const dispatch = useAppDispatch(); @@ -55,6 +59,20 @@ export const ClerkEnrollmentContactRequestPage: FC = () => { } }, [dispatch, status, params.enrollmentContactRequestId]); + useEffect(() => { + if ( + createStatus === APIResponseStatus.Success && + params.enrollmentContactRequestId + ) { + navigate( + AppRoutes.ClerkEnrollmentAppointmentPage.replace( + ':enrollmentAppointmentId', + params.enrollmentContactRequestId, + ), + ); + } + }, [dispatch, navigate, params.enrollmentContactRequestId, createStatus]); + const isLoading = status === APIResponseStatus.InProgress; const isSavingDisabled = isLoading; @@ -62,6 +80,10 @@ export const ClerkEnrollmentContactRequestPage: FC = () => { return <>; } + const onSubmit = () => { + dispatch(createClerkEnrollmentAppointment(enrollment.id)); + }; + return ( { variant={Variant.Contained} color={Color.Secondary} disabled={isSavingDisabled} + onClick={onSubmit} > {translateCommon('save')} diff --git a/frontend/packages/vkt/src/redux/reducers/clerkEnrollmentContactRequest.ts b/frontend/packages/vkt/src/redux/reducers/clerkEnrollmentContactRequest.ts index 5461b0510..311424ffb 100644 --- a/frontend/packages/vkt/src/redux/reducers/clerkEnrollmentContactRequest.ts +++ b/frontend/packages/vkt/src/redux/reducers/clerkEnrollmentContactRequest.ts @@ -34,6 +34,15 @@ const clerkEnrollmentContactRequestSlice = createSlice({ createClerkEnrollmentAppointment(state, _action: PayloadAction) { state.createStatus = APIResponseStatus.InProgress; }, + storeCreateClerkEnrollmentAppointment( + state, + _action: PayloadAction, + ) { + state.createStatus = APIResponseStatus.Success; + }, + rejectCreateClerkEnrollmentAppointment(state) { + state.createStatus = APIResponseStatus.Error; + }, }, }); @@ -43,4 +52,7 @@ export const { rejectClerkEnrollmentContactRequest, storeClerkEnrollmentContactRequest, loadClerkEnrollmentContactRequest, + createClerkEnrollmentAppointment, + storeCreateClerkEnrollmentAppointment, + rejectCreateClerkEnrollmentAppointment, } = clerkEnrollmentContactRequestSlice.actions; diff --git a/frontend/packages/vkt/src/redux/sagas/clerkEnrollmentContactRequest.ts b/frontend/packages/vkt/src/redux/sagas/clerkEnrollmentContactRequest.ts index 6e7e38e6f..35de27dc1 100644 --- a/frontend/packages/vkt/src/redux/sagas/clerkEnrollmentContactRequest.ts +++ b/frontend/packages/vkt/src/redux/sagas/clerkEnrollmentContactRequest.ts @@ -6,12 +6,35 @@ import axiosInstance from 'configs/axios'; import { APIEndpoints } from 'enums/api'; import { ClerkEnrollmentContactResponse } from 'interfaces/clerkEnrollment'; import { + createClerkEnrollmentAppointment, loadClerkEnrollmentContactRequest, rejectClerkEnrollmentContactRequest, + rejectCreateClerkEnrollmentAppointment, storeClerkEnrollmentContactRequest, + storeCreateClerkEnrollmentAppointment, } from 'redux/reducers/clerkEnrollmentContactRequest'; import { SerializationUtils } from 'utils/serialization'; +function* createClerkEnrollmentAppointmentSaga(action: PayloadAction) { + try { + const contactId = action.payload; + const saveUrl = `${APIEndpoints.ClerkEnrollmentContactRequest}/${contactId}/convertToAppointment`; + + const response: AxiosResponse = yield call( + axiosInstance.post, + saveUrl, + ); + const enrollment = + SerializationUtils.deserializeClerkEnrollmentContactRequest( + response.data, + ); + + yield put(storeCreateClerkEnrollmentAppointment(enrollment)); + } catch (error) { + yield put(rejectCreateClerkEnrollmentAppointment()); + } +} + function* loadClerkEnrollmentContactRequestSaga(action: PayloadAction) { try { const contactId = action.payload; @@ -37,4 +60,8 @@ export function* watchClerkEnrollmentContactRequest() { loadClerkEnrollmentContactRequest.type, loadClerkEnrollmentContactRequestSaga, ); + yield takeLatest( + createClerkEnrollmentAppointment.type, + createClerkEnrollmentAppointmentSaga, + ); }