diff --git a/backend/vkt/db/4_init.sql b/backend/vkt/db/4_init.sql index 43446d6c7..9184bad1e 100644 --- a/backend/vkt/db/4_init.sql +++ b/backend/vkt/db/4_init.sql @@ -485,7 +485,7 @@ INSERT INTO enrollment_appointment(person_id, examiner_id, examiner_exam_event_i partial_exam_speaking, partial_exam_speech_comprehension, partial_exam_writing, partial_exam_reading_comprehension, status, digital_certificate_consent, email, phone_number, street, postal_code, town, country, first_name, last_name, auth_hash, auth_hash_expires, auth_hash_sent) -VALUES (1, 1, 1, +VALUES (null, 1, 1, true, true, true, true, true, true, true, 'WAITING_AUTHENTICATION', false, diff --git a/backend/vkt/src/main/java/fi/oph/vkt/api/dto/examiner/ExaminerEnrollmentExamEventDTO.java b/backend/vkt/src/main/java/fi/oph/vkt/api/dto/examiner/ExaminerEnrollmentExamEventDTO.java new file mode 100644 index 000000000..24bf314ae --- /dev/null +++ b/backend/vkt/src/main/java/fi/oph/vkt/api/dto/examiner/ExaminerEnrollmentExamEventDTO.java @@ -0,0 +1,6 @@ +package fi.oph.vkt.api.dto.examiner; + +import jakarta.validation.constraints.NotNull; +import lombok.NonNull; + +public record ExaminerEnrollmentExamEventDTO(@NonNull @NotNull Long id) {} diff --git a/backend/vkt/src/main/java/fi/oph/vkt/api/examiner/ExaminerEnrollmentController.java b/backend/vkt/src/main/java/fi/oph/vkt/api/examiner/ExaminerEnrollmentController.java index 9bac623b0..1c4a14f85 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/api/examiner/ExaminerEnrollmentController.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/api/examiner/ExaminerEnrollmentController.java @@ -6,6 +6,7 @@ import fi.oph.vkt.api.dto.examiner.ExaminerEnrollmentAppointmentDTO; import fi.oph.vkt.api.dto.examiner.ExaminerEnrollmentAppointmentHistoryDTO; import fi.oph.vkt.api.dto.examiner.ExaminerEnrollmentAppointmentUpdateDTO; +import fi.oph.vkt.api.dto.examiner.ExaminerEnrollmentExamEventDTO; import fi.oph.vkt.api.dto.examiner.ExaminerEnrollmentGradesDTO; import fi.oph.vkt.service.ExaminerEnrollmentService; import io.swagger.v3.oas.annotations.Operation; @@ -66,9 +67,10 @@ public void deleteEnrollmentContactRequest( @Operation(tags = TAG_ENROLLMENT, summary = "Convert enrollment contact request to enrollment appointment") public ExaminerEnrollmentAppointmentDTO enrollmentContactRequestToAppointment( @PathVariable final String oid, - @PathVariable final long enrollmentContactId + @PathVariable final long enrollmentContactId, + @RequestBody @Valid final ExaminerEnrollmentExamEventDTO examEvent ) { - return examinerEnrollmentService.convertToAppointment(oid, enrollmentContactId); + return examinerEnrollmentService.convertToAppointment(oid, enrollmentContactId, examEvent); } @GetMapping(path = "/appointment/{enrollmentAppointmentId:\\d+}", consumes = ALL_VALUE) diff --git a/backend/vkt/src/main/java/fi/oph/vkt/service/ExaminerEnrollmentService.java b/backend/vkt/src/main/java/fi/oph/vkt/service/ExaminerEnrollmentService.java index ba8be32b9..a346fd3e6 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/service/ExaminerEnrollmentService.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/service/ExaminerEnrollmentService.java @@ -4,6 +4,7 @@ import fi.oph.vkt.api.dto.examiner.ExaminerEnrollmentAppointmentDTO; import fi.oph.vkt.api.dto.examiner.ExaminerEnrollmentAppointmentHistoryDTO; import fi.oph.vkt.api.dto.examiner.ExaminerEnrollmentAppointmentUpdateDTO; +import fi.oph.vkt.api.dto.examiner.ExaminerEnrollmentExamEventDTO; import fi.oph.vkt.api.dto.examiner.ExaminerEnrollmentGradesDTO; import fi.oph.vkt.audit.AuditService; import fi.oph.vkt.audit.VktOperation; @@ -20,6 +21,7 @@ import fi.oph.vkt.util.UUIDSource; import fi.oph.vkt.util.exception.APIException; import fi.oph.vkt.util.exception.APIExceptionType; +import jakarta.validation.Valid; import java.io.IOException; import java.time.LocalDateTime; import java.util.List; @@ -91,15 +93,21 @@ public ClerkEnrollmentContactRequestDTO getEnrollmentContactRequest( } @Transactional - public ExaminerEnrollmentAppointmentDTO convertToAppointment(final String oid, final long enrollmentContactId) { + public ExaminerEnrollmentAppointmentDTO convertToAppointment( + final String oid, + final long enrollmentContactId, + final ExaminerEnrollmentExamEventDTO examEvent + ) { final EnrollmentAppointment enrollmentAppointment = enrollmentAppointmentRepository.getReferenceById( enrollmentContactId ); + final ExaminerExamEvent examinerExamEvent = examinerExamEventRepository.getReferenceById(examEvent.id()); checkExaminerOid(enrollmentAppointment, oid); final String baseUrlAPI = environment.getRequiredProperty("app.base-url.api"); enrollmentAppointment.setStatus(EnrollmentAppointmentStatus.ENROLLMENT_CREATED); + enrollmentAppointment.setExaminerExamEvent(examinerExamEvent); if (enrollmentAppointment.getAuthHash() == null) { enrollmentAppointment.setAuthHash(uuidSource.getRandomNonce()); diff --git a/frontend/packages/vkt/public/i18n/fi-FI/clerk.json b/frontend/packages/vkt/public/i18n/fi-FI/clerk.json index b45f519b1..1b34685b2 100644 --- a/frontend/packages/vkt/public/i18n/fi-FI/clerk.json +++ b/frontend/packages/vkt/public/i18n/fi-FI/clerk.json @@ -99,6 +99,14 @@ } }, "clerkcontactRequest": { + "contactRequest": "Yhteydenottopyyntö", + "contactFields": "Yhteystiedot", + "lastName": "Sukunimi", + "firstName": "Etunimi", + "email": "Sähköpostiosoite", + "phoneNumber": "Puhelinnumero", + "partialExams": "Osakokeet, jotka haluan suorittaa", + "previousExams": "Osallistunut aiempiin tutkintoihin?", "createEnrollment": "Luo ilmoittautuminen", "contactDetails": "Yhteydenoton tiedot", "message": "Viesti", @@ -106,7 +114,10 @@ "deleteAreYouSure": "Haluatko varmasti poistaa yhteydenoton?", "deleteDescription": "Toimintoa ei voi peruuttaa!", "deleteContactRequest": "Poista yhteydenotto", - "deleteContactRequestSuccess": "Yhteydenotto poistettu" + "deleteContactRequestSuccess": "Yhteydenotto poistettu", + "selectExamHelp": "Huom. voit valita vain tutkintotilaisuuden, jolle on määritetty tarkka osoite ja alkamisaika", + "chooseExamAndCreate": "Valitse tutkintotilaisuus ja luo ilmoittautuminen", + "chooseExam": "Valitse tutkintotilaisuus" }, "clerkEnrollmentListing": { "header": { diff --git a/frontend/packages/vkt/src/components/clerkEnrollment/appointment/ClerkEnrollmentAppointmentDetails.tsx b/frontend/packages/vkt/src/components/clerkEnrollment/appointment/ClerkEnrollmentAppointmentDetails.tsx index 4de637d95..b00ae702f 100644 --- a/frontend/packages/vkt/src/components/clerkEnrollment/appointment/ClerkEnrollmentAppointmentDetails.tsx +++ b/frontend/packages/vkt/src/components/clerkEnrollment/appointment/ClerkEnrollmentAppointmentDetails.tsx @@ -19,7 +19,6 @@ import { ClerkEnrollmentTextFieldEnum } from 'enums/clerkEnrollment'; import { useNavigationProtection } from 'hooks/useNavigationProtection'; import { ClerkEnrollmentAppointment } from 'interfaces/clerkEnrollment'; import { PartialExamsAndSkills } from 'interfaces/common/enrollment'; -import { ExaminerExamEvent } from 'interfaces/examinerExamEvent'; import { cancelClerkEnrollmentAppointment, resetClerkEnrollmentDetails, @@ -31,12 +30,10 @@ import { EnrollmentUtils } from 'utils/enrollment'; export const ClerkEnrollmentAppointmentDetails = ({ enrollment, - examEvents, editMode, oid, }: { enrollment: ClerkEnrollmentAppointment; - examEvents: Array; editMode: boolean; oid: string; }) => { @@ -53,9 +50,6 @@ export const ClerkEnrollmentAppointmentDetails = ({ const [enrollmentDetails, setEnrollmentDetails] = useState< ClerkEnrollmentAppointment | undefined >(enrollment); - const [newExamEvent, setNewExamEvent] = useState< - ExaminerExamEvent | undefined - >(enrollment.examEvent); const [hasLocalChanges, setHasLocalChanges] = useState(false); const [currentUIMode, setCurrentUIMode] = useState( editMode ? UIMode.Edit : UIMode.View, @@ -154,17 +148,6 @@ export const ClerkEnrollmentAppointmentDetails = ({ }); }; - const handleExamEventChange = (examEvent: string | undefined) => { - if (examEvent) { - const foundExamEvent = examEvents.find((e) => e.id === +examEvent); - - if (foundExamEvent) { - setHasLocalChanges(true); - setNewExamEvent(foundExamEvent); - } - } - }; - const handleSaveButtonClick = () => { dispatch( updateClerkEnrollmentAppointment({ @@ -174,7 +157,7 @@ export const ClerkEnrollmentAppointmentDetails = ({ understandingSkill: enrollmentDetails.speechComprehensionPartialExam && enrollmentDetails.readingComprehensionPartialExam, - examEvent: newExamEvent ?? enrollment.examEvent, + examEvent: enrollment.examEvent, }, }), ); @@ -242,9 +225,6 @@ export const ClerkEnrollmentAppointmentDetails = ({ { - const translateCommon = useCommonTranslation(); - const translateMunicipality = useKoodistoMunicipalitiesTranslation(); - const describeExamEvent = ({ - language, - date, - examTime, - municipality, - }: ExaminerExamEvent) => { - const dateStr = DateUtils.formatOptionalDate(date); - - return [ - translateCommon(`examLanguage.${language}`), - examTime ? `${dateStr} ${examTime}` : dateStr, - translateMunicipality(municipality.code), - ].join(', '); - }; - - return describeExamEvent; -}; - const ExamAndEnrollmentDetailsSection = ({ enrollment, isViewMode, - examEvents, - newExamEvent, - onExamEventChange, onCheckboxFieldChange, editDisabled, openGradeModal, @@ -357,9 +330,6 @@ const ExamAndEnrollmentDetailsSection = ({ }: { enrollment: ClerkEnrollmentAppointment; isViewMode: boolean; - examEvents: Array; - newExamEvent: ExaminerExamEvent | undefined; - onExamEventChange: (value?: string) => void; onCheckboxFieldChange: ( field: | keyof PartialExamsAndSkills @@ -381,44 +351,23 @@ const ExamAndEnrollmentDetailsSection = ({ const translateMunicipality = useKoodistoMunicipalitiesTranslation(); const translateCommon = useCommonTranslation(); - const describeExamEvent = useExamEventDescription(); - const examEventToOption = (examEvent: ExaminerExamEvent) => ({ - value: examEvent.id.toString(), - label: describeExamEvent(examEvent), - }); - return ( <>

Tutkinnon tiedot

- {isViewMode ? ( - enrollment.examEvent && ( -
-

Tutkinnon kieli, aika ja paikka

- - {translateCommon(`examLanguage.${enrollment.examEvent.language}`)} - {', '} - {DateTimeUtils.renderDate(enrollment.examEvent.date)} - {', '} - {translateMunicipality(enrollment.examEvent.municipality.code)} - {', '} - {enrollment.examEvent.location} - -
- ) - ) : ( -
- a.label.localeCompare(b.label))} - value={newExamEvent ? examEventToOption(newExamEvent) : null} - variant={TextFieldVariant.Outlined} - onChange={onExamEventChange} - /> + {enrollment.examEvent && ( +
+

Tutkinnon kieli, aika ja paikka

+ + {translateCommon(`examLanguage.${enrollment.examEvent.language}`)} + {', '} + {DateTimeUtils.renderDate(enrollment.examEvent.date)} + {', '} + {translateMunicipality(enrollment.examEvent.municipality.code)} + {', '} + {enrollment.examEvent.location} +
)} {isViewMode ? ( @@ -663,9 +612,6 @@ const PaymentLinkModal = ({ export const ClerkEnrollmentAppointmentDetailsFields = ({ enrollment, - examEvents, - newExamEvent, - onExamEventChange, editDisabled, isViewMode, oid, @@ -675,14 +621,11 @@ export const ClerkEnrollmentAppointmentDetailsFields = ({ showFieldErrorBeforeChange, }: { enrollment: ClerkEnrollmentAppointment; - examEvents: Array; - newExamEvent: ExaminerExamEvent | undefined; editDisabled: boolean; isViewMode: boolean; oid: string; topControlButtons: JSX.Element; showFieldErrorBeforeChange: boolean; - onExamEventChange: (value?: string) => void; onTextFieldChange: ( field: ClerkEnrollmentTextFieldEnum, ) => (event: ChangeEvent) => void; @@ -816,10 +759,7 @@ export const ClerkEnrollmentAppointmentDetailsFields = ({ setGradeModalOpen(true)} diff --git a/frontend/packages/vkt/src/hooks/useExamEventDescription.ts b/frontend/packages/vkt/src/hooks/useExamEventDescription.ts new file mode 100644 index 000000000..51e4eca4d --- /dev/null +++ b/frontend/packages/vkt/src/hooks/useExamEventDescription.ts @@ -0,0 +1,28 @@ +import { DateUtils } from 'shared/utils'; + +import { + useCommonTranslation, + useKoodistoMunicipalitiesTranslation, +} from 'configs/i18n'; +import { ExaminerExamEvent } from 'interfaces/examinerExamEvent'; + +export const useExamEventDescription = () => { + const translateCommon = useCommonTranslation(); + const translateMunicipality = useKoodistoMunicipalitiesTranslation(); + const describeExamEvent = ({ + language, + date, + examTime, + municipality, + }: ExaminerExamEvent) => { + const dateStr = DateUtils.formatOptionalDate(date); + + return [ + translateCommon(`examLanguage.${language}`), + examTime ? `${dateStr} ${examTime}` : dateStr, + translateMunicipality(municipality.code), + ].join(', '); + }; + + return describeExamEvent; +}; diff --git a/frontend/packages/vkt/src/pages/ClerkEnrollmentAppointmentOverviewPage.tsx b/frontend/packages/vkt/src/pages/ClerkEnrollmentAppointmentOverviewPage.tsx index efd83802e..81dafc620 100644 --- a/frontend/packages/vkt/src/pages/ClerkEnrollmentAppointmentOverviewPage.tsx +++ b/frontend/packages/vkt/src/pages/ClerkEnrollmentAppointmentOverviewPage.tsx @@ -11,7 +11,6 @@ import { AppRoutes } from 'enums/app'; import { loadClerkEnrollmentAppointment, loadClerkEnrollmentAppointmentGrades, - loadExaminerExamEvents, resetClerkEnrollmentDetailsToInitialState, } from 'redux/reducers/clerkEnrollmentAppointment'; import { clerkEnrollmentAppointmentSelector } from 'redux/selectors/clerkEnrollmentAppointment'; @@ -24,8 +23,9 @@ export const ClerkEnrollmentAppointmentOverviewPage: FC< ClerkEnrollmentAppointmentOverviewPageProps > = ({ editMode }) => { // Redux - const { status, gradesStatus, examEventsStatus, examEvents, enrollment } = - useAppSelector(clerkEnrollmentAppointmentSelector); + const { status, gradesStatus, enrollment } = useAppSelector( + clerkEnrollmentAppointmentSelector, + ); const dispatch = useAppDispatch(); const params = useParams(); @@ -69,12 +69,6 @@ export const ClerkEnrollmentAppointmentOverviewPage: FC< } }, [dispatch, status, params.enrollmentAppointmentId, params.oid]); - useEffect(() => { - if (examEventsStatus === APIResponseStatus.NotStarted && params.oid) { - dispatch(loadExaminerExamEvents(params.oid)); - } - }, [dispatch, examEventsStatus, params.oid]); - useEffect(() => { if ( gradesStatus === APIResponseStatus.NotStarted && @@ -102,7 +96,6 @@ export const ClerkEnrollmentAppointmentOverviewPage: FC< )} diff --git a/frontend/packages/vkt/src/pages/ClerkEnrollmentContactRequestPage.tsx b/frontend/packages/vkt/src/pages/ClerkEnrollmentContactRequestPage.tsx index fce7a1710..62f68d851 100644 --- a/frontend/packages/vkt/src/pages/ClerkEnrollmentContactRequestPage.tsx +++ b/frontend/packages/vkt/src/pages/ClerkEnrollmentContactRequestPage.tsx @@ -1,7 +1,8 @@ import { Box, Divider, Grid, Paper } from '@mui/material'; -import { FC, useEffect } from 'react'; +import { FC, useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router'; import { + ComboBox, CustomButton, H1, H2, @@ -14,6 +15,7 @@ import { Color, Duration, Severity, + TextFieldVariant, Variant, } from 'shared/enums'; import { useDialog, useToast } from 'shared/hooks'; @@ -22,19 +24,27 @@ import { TopControls } from 'components/clerkExamEvent/overview/TopControls'; import { useClerkTranslation, useCommonTranslation } from 'configs/i18n'; import { useAppDispatch, useAppSelector } from 'configs/redux'; import { AppRoutes } from 'enums/app'; +import { useExamEventDescription } from 'hooks/useExamEventDescription'; +import { ExaminerExamEvent } from 'interfaces/examinerExamEvent'; import { createClerkEnrollmentAppointment, deleteClerkEnrollmentContactRequest, loadClerkEnrollmentContactRequest, + loadExaminerExamEvents, resetClerkEnrollmentContactRequestToInitialState, } from 'redux/reducers/clerkEnrollmentContactRequest'; import { resetExaminerDetailsToInitialState } from 'redux/reducers/examinerDetails'; import { clerkEnrollmentContactRequestSelector } from 'redux/selectors/clerkEnrollmentContactRequest'; export const ClerkEnrollmentContactRequestPage: FC = () => { - const { status, deleteStatus, createStatus, enrollment } = useAppSelector( - clerkEnrollmentContactRequestSelector, - ); + const { + status, + examEventsStatus, + examEvents, + deleteStatus, + createStatus, + enrollment, + } = useAppSelector(clerkEnrollmentContactRequestSelector); const { t } = useClerkTranslation({ keyPrefix: 'vkt.component.clerkcontactRequest', }); @@ -43,10 +53,21 @@ export const ClerkEnrollmentContactRequestPage: FC = () => { const navigate = useNavigate(); const { showDialog } = useDialog(); const { showToast } = useToast(); + const describeExamEvent = useExamEventDescription(); + + const [newExamEvent, setNewExamEvent] = useState< + ExaminerExamEvent | undefined + >(); const dispatch = useAppDispatch(); const backTo = AppRoutes.ExaminerHomePage.replace(':oid', params.oid || ''); + useEffect(() => { + if (examEventsStatus === APIResponseStatus.NotStarted && params.oid) { + dispatch(loadExaminerExamEvents(params.oid)); + } + }, [dispatch, examEventsStatus, params.oid]); + useEffect(() => { if (deleteStatus === APIResponseStatus.Success && params.oid) { dispatch(resetExaminerDetailsToInitialState()); @@ -125,14 +146,32 @@ export const ClerkEnrollmentContactRequestPage: FC = () => { } const onSubmit = () => { - dispatch( - createClerkEnrollmentAppointment({ - id: enrollment.id, - oid: params.oid || '', - }), - ); + if (params.oid && newExamEvent?.id) { + dispatch( + createClerkEnrollmentAppointment({ + id: enrollment.id, + oid: params.oid, + examEvent: newExamEvent.id, + }), + ); + } + }; + + const handleExamEventChange = (examEvent: string | undefined) => { + if (examEvent) { + const foundExamEvent = examEvents.find((e) => e.id === +examEvent); + + if (foundExamEvent) { + setNewExamEvent(foundExamEvent); + } + } }; + const examEventToOption = (examEvent: ExaminerExamEvent) => ({ + value: examEvent.id.toString(), + label: describeExamEvent(examEvent), + }); + const openDeleteDialog = () => { showDialog({ title: t('deleteAreYouSure'), @@ -170,29 +209,29 @@ export const ClerkEnrollmentContactRequestPage: FC = () => {
-

Yhteydenottopyyntö

+

{t('contactRequest')}

-

Yhteystiedot

+

{t('contactFields')}

-

Sukunimi

+

{t('lastName')}

{enrollment.lastName}
-

Etunimi

+

{t('firstName')}

{enrollment.firstName}
-

Sähköpostiosoite

+

{t('email')}

{enrollment.email}
-

Puhelinnumero

+

{t('phoneNumber')}

{enrollment.phoneNumber}
@@ -208,12 +247,12 @@ export const ClerkEnrollmentContactRequestPage: FC = () => { {!enrollment.isFullExam && (
-

Osakokeet, jotka haluan suorittaa

+

{t('partialExams')}

{enrollment.partialExamSelection}
)}
-

Osallistunut aiempiin tutkintoihin?

+

{t('previousExams')}

{enrollment.hasPreviousEnrollment ? translateCommon('yes') @@ -224,27 +263,43 @@ export const ClerkEnrollmentContactRequestPage: FC = () => {

{t('message')}

{enrollment.message}
-
- + +
+

{t('chooseExamAndCreate')}

+

{t('chooseExam')}

+ {t('selectExamHelp')} +
+ a.label.localeCompare(b.label))} + value={newExamEvent ? examEventToOption(newExamEvent) : null} + variant={TextFieldVariant.Outlined} + onChange={handleExamEventChange} + /> +
+ - {t('deleteContactRequest')} + {t('createEnrollment')} - +
+
+ - {t('createEnrollment')} + {t('deleteContactRequest')}
diff --git a/frontend/packages/vkt/src/redux/reducers/clerkEnrollmentAppointment.ts b/frontend/packages/vkt/src/redux/reducers/clerkEnrollmentAppointment.ts index 9e2b28c1f..3e8cb6a21 100644 --- a/frontend/packages/vkt/src/redux/reducers/clerkEnrollmentAppointment.ts +++ b/frontend/packages/vkt/src/redux/reducers/clerkEnrollmentAppointment.ts @@ -6,7 +6,6 @@ import { ClerkEnrollmentAppointmentGrades, ClerkEnrollmentAppointmentHistory, } from 'interfaces/clerkEnrollment'; -import { ExaminerExamEvent } from 'interfaces/examinerExamEvent'; interface ClerkEnrollmentAppointmentState { status: APIResponseStatus; @@ -17,9 +16,7 @@ interface ClerkEnrollmentAppointmentState { enrollmentHistory?: Array; gradesStatus: APIResponseStatus; gradesSaveStatus: APIResponseStatus; - examEventsStatus: APIResponseStatus; sendLinkStatus: APIResponseStatus; - examEvents: Array; grades?: ClerkEnrollmentAppointmentGrades; } @@ -30,9 +27,7 @@ const initialState: ClerkEnrollmentAppointmentState = { cancelStatus: APIResponseStatus.NotStarted, gradesStatus: APIResponseStatus.NotStarted, gradesSaveStatus: APIResponseStatus.NotStarted, - examEventsStatus: APIResponseStatus.NotStarted, sendLinkStatus: APIResponseStatus.NotStarted, - examEvents: [], grades: { version: 0, speakingPartialExam: { @@ -58,16 +53,6 @@ const clerkEnrollmentAppointmentSlice = createSlice({ name: 'clerkEnrollmentAppointment', initialState, reducers: { - loadExaminerExamEvents(state, _action: PayloadAction) { - state.examEventsStatus = APIResponseStatus.InProgress; - }, - storeExaminerExamEvents( - state, - action: PayloadAction>, - ) { - state.examEvents = action.payload; - state.examEventsStatus = APIResponseStatus.Success; - }, loadClerkEnrollmentAppointment( state, _action: PayloadAction<{ @@ -113,7 +98,6 @@ const clerkEnrollmentAppointmentSlice = createSlice({ state.updateStatus = initialState.updateStatus; state.status = initialState.status; state.gradesSaveStatus = initialState.gradesSaveStatus; - state.examEventsStatus = initialState.examEventsStatus; state.sendLinkStatus = initialState.sendLinkStatus; }, sendClerkEnrollmentAppointmentAuthLink( @@ -198,8 +182,6 @@ const clerkEnrollmentAppointmentSlice = createSlice({ export const clerkEnrollmentAppointmentReducer = clerkEnrollmentAppointmentSlice.reducer; export const { - loadExaminerExamEvents, - storeExaminerExamEvents, storeClerkEnrollmentAppointmentUpdate, rejectClerkEnrollmentAppointment, storeClerkEnrollmentAppointment, diff --git a/frontend/packages/vkt/src/redux/reducers/clerkEnrollmentContactRequest.ts b/frontend/packages/vkt/src/redux/reducers/clerkEnrollmentContactRequest.ts index 2cb7e4f35..411024a21 100644 --- a/frontend/packages/vkt/src/redux/reducers/clerkEnrollmentContactRequest.ts +++ b/frontend/packages/vkt/src/redux/reducers/clerkEnrollmentContactRequest.ts @@ -2,24 +2,39 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { APIResponseStatus } from 'shared/enums'; import { ClerkEnrollmentContact } from 'interfaces/clerkEnrollment'; +import { ExaminerExamEvent } from 'interfaces/examinerExamEvent'; export interface ClerkEnrollmentContactRequestState { status: APIResponseStatus; deleteStatus: APIResponseStatus; enrollment?: ClerkEnrollmentContact; createStatus: APIResponseStatus; + examEventsStatus: APIResponseStatus; + examEvents: Array; } const initialState: ClerkEnrollmentContactRequestState = { status: APIResponseStatus.NotStarted, createStatus: APIResponseStatus.NotStarted, deleteStatus: APIResponseStatus.NotStarted, + examEventsStatus: APIResponseStatus.NotStarted, + examEvents: [], }; const clerkEnrollmentContactRequestSlice = createSlice({ name: 'clerkEnrollmentContactRequest', initialState, reducers: { + loadExaminerExamEvents(state, _action: PayloadAction) { + state.examEventsStatus = APIResponseStatus.InProgress; + }, + storeExaminerExamEvents( + state, + action: PayloadAction>, + ) { + state.examEvents = action.payload; + state.examEventsStatus = APIResponseStatus.Success; + }, loadClerkEnrollmentContactRequest( state, _action: PayloadAction<{ @@ -44,6 +59,7 @@ const clerkEnrollmentContactRequestSlice = createSlice({ _action: PayloadAction<{ id: number; oid: string; + examEvent: number; }>, ) { state.createStatus = APIResponseStatus.InProgress; @@ -78,6 +94,8 @@ const clerkEnrollmentContactRequestSlice = createSlice({ export const clerkEnrollmentContactRequestReducer = clerkEnrollmentContactRequestSlice.reducer; export const { + storeExaminerExamEvents, + loadExaminerExamEvents, rejectClerkEnrollmentContactRequest, storeClerkEnrollmentContactRequest, loadClerkEnrollmentContactRequest, diff --git a/frontend/packages/vkt/src/redux/sagas/clerkEnrollmentAppointment.ts b/frontend/packages/vkt/src/redux/sagas/clerkEnrollmentAppointment.ts index 6ce533a3c..0b6e94acd 100644 --- a/frontend/packages/vkt/src/redux/sagas/clerkEnrollmentAppointment.ts +++ b/frontend/packages/vkt/src/redux/sagas/clerkEnrollmentAppointment.ts @@ -10,14 +10,12 @@ import { ClerkEnrollmentAppointmentHistoryResponse, ClerkEnrollmentAppointmentResponse, } from 'interfaces/clerkEnrollment'; -import { ExaminerExamEventResponse } from 'interfaces/examinerExamEvent'; import { setAPIError } from 'redux/reducers/APIError'; import { cancelClerkEnrollmentAppointment, loadClerkEnrollmentAppointment, loadClerkEnrollmentAppointmentGrades, loadClerkEnrollmentAppointmentHistory, - loadExaminerExamEvents, rejectClerkEnrollmentAppointment, sendClerkEnrollmentAppointmentAuthLink, storeCancelClerkEnrollmentAppointment, @@ -26,7 +24,6 @@ import { storeClerkEnrollmentAppointmentGrades, storeClerkEnrollmentAppointmentGradesUpsert, storeClerkEnrollmentAppointmentUpdate, - storeExaminerExamEvents, storeLoadClerkEnrollmentAppointmentHistory, storeUpdateClerkEnrollmentAppointment, updateClerkEnrollmentAppointment, @@ -206,23 +203,6 @@ function* cancelClerkEnrollmentAppointmentSaga( } } -function* loadExaminerExamEventsSaga(action: PayloadAction) { - try { - const oid = action.payload; - const loadUrl = APIEndpoints.ExaminerExamEvent.replace(/:oid/, oid); - - const response: AxiosResponse> = - yield call(axiosInstance.get, loadUrl); - const examinerExamEvents = SerializationUtils.deserializeExaminerExamEvents( - response.data, - ); - - yield put(storeExaminerExamEvents(examinerExamEvents)); - } catch (error) { - //yield put(rejectClerkEnrollmentAppointment()); - } -} - function* loadClerkEnrollmentAppointmentHistorySaga( action: PayloadAction<{ enrollmentId: number; @@ -262,7 +242,6 @@ export function* watchClerkEnrollmentAppointment() { cancelClerkEnrollmentAppointment.type, cancelClerkEnrollmentAppointmentSaga, ); - yield takeLatest(loadExaminerExamEvents.type, loadExaminerExamEventsSaga); yield takeLatest( loadClerkEnrollmentAppointment.type, loadClerkEnrollmentAppointmentSaga, diff --git a/frontend/packages/vkt/src/redux/sagas/clerkEnrollmentContactRequest.ts b/frontend/packages/vkt/src/redux/sagas/clerkEnrollmentContactRequest.ts index 8b9169381..1d2280617 100644 --- a/frontend/packages/vkt/src/redux/sagas/clerkEnrollmentContactRequest.ts +++ b/frontend/packages/vkt/src/redux/sagas/clerkEnrollmentContactRequest.ts @@ -5,15 +5,18 @@ import { call, put, takeLatest } from 'redux-saga/effects'; import axiosInstance from 'configs/axios'; import { APIEndpoints } from 'enums/api'; import { ClerkEnrollmentContactResponse } from 'interfaces/clerkEnrollment'; +import { ExaminerExamEventResponse } from 'interfaces/examinerExamEvent'; import { createClerkEnrollmentAppointment, deleteClerkEnrollmentContactRequest, loadClerkEnrollmentContactRequest, + loadExaminerExamEvents, rejectClerkEnrollmentContactRequest, rejectCreateClerkEnrollmentAppointment, storeClerkEnrollmentContactRequest, storeCreateClerkEnrollmentAppointment, storeDeleteClerkEnrollmentContactRequest, + storeExaminerExamEvents, } from 'redux/reducers/clerkEnrollmentContactRequest'; import { SerializationUtils } from 'utils/serialization'; @@ -21,10 +24,11 @@ function* createClerkEnrollmentAppointmentSaga( action: PayloadAction<{ id: number; oid: string; + examEvent: number; }>, ) { try { - const { id, oid } = action.payload; + const { id, oid, examEvent } = action.payload; const saveUrl = `${APIEndpoints.ExaminerEnrollmentContactRequest.replace( /:oid/, oid, @@ -33,6 +37,7 @@ function* createClerkEnrollmentAppointmentSaga( const response: AxiosResponse = yield call( axiosInstance.post, saveUrl, + { id: examEvent }, ); const enrollment = SerializationUtils.deserializeClerkEnrollmentContactRequest( @@ -66,6 +71,23 @@ function* deleteClerkEnrollmentContactRequestSaga( } } +function* loadExaminerExamEventsSaga(action: PayloadAction) { + try { + const oid = action.payload; + const loadUrl = APIEndpoints.ExaminerExamEvent.replace(/:oid/, oid); + + const response: AxiosResponse> = + yield call(axiosInstance.get, loadUrl); + const examinerExamEvents = SerializationUtils.deserializeExaminerExamEvents( + response.data, + ); + + yield put(storeExaminerExamEvents(examinerExamEvents)); + } catch (error) { + //yield put(rejectClerkEnrollmentAppointment()); + } +} + function* loadClerkEnrollmentContactRequestSaga( action: PayloadAction<{ id: number; @@ -99,6 +121,7 @@ export function* watchClerkEnrollmentContactRequest() { loadClerkEnrollmentContactRequest.type, loadClerkEnrollmentContactRequestSaga, ); + yield takeLatest(loadExaminerExamEvents.type, loadExaminerExamEventsSaga); yield takeLatest( deleteClerkEnrollmentContactRequest.type, deleteClerkEnrollmentContactRequestSaga,