Skip to content

Commit

Permalink
VKT(Backend & Frontend): Move exam event selection to contact request…
Browse files Browse the repository at this point in the history
… handling
  • Loading branch information
jrkkp committed Dec 16, 2024
1 parent 029be22 commit 5ca29c6
Show file tree
Hide file tree
Showing 14 changed files with 204 additions and 179 deletions.
2 changes: 1 addition & 1 deletion backend/vkt/db/4_init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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) {}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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());
Expand Down
13 changes: 12 additions & 1 deletion frontend/packages/vkt/public/i18n/fi-FI/clerk.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,25 @@
}
},
"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",
"wantFullExam": "Haluan suorittaa koko tutkinnon?",
"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": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -31,12 +30,10 @@ import { EnrollmentUtils } from 'utils/enrollment';

export const ClerkEnrollmentAppointmentDetails = ({
enrollment,
examEvents,
editMode,
oid,
}: {
enrollment: ClerkEnrollmentAppointment;
examEvents: Array<ExaminerExamEvent>;
editMode: boolean;
oid: string;
}) => {
Expand All @@ -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,
Expand Down Expand Up @@ -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({
Expand All @@ -174,7 +157,7 @@ export const ClerkEnrollmentAppointmentDetails = ({
understandingSkill:
enrollmentDetails.speechComprehensionPartialExam &&
enrollmentDetails.readingComprehensionPartialExam,
examEvent: newExamEvent ?? enrollment.examEvent,
examEvent: enrollment.examEvent,
},
}),
);
Expand Down Expand Up @@ -242,9 +225,6 @@ export const ClerkEnrollmentAppointmentDetails = ({
<ClerkEnrollmentAppointmentDetailsFields
showFieldErrorBeforeChange={false}
enrollment={enrollmentDetails}
examEvents={examEvents}
newExamEvent={newExamEvent}
onExamEventChange={handleExamEventChange}
onTextFieldChange={handleTextFieldChange}
onCheckboxFieldChange={handleCheckboxFieldChange}
editDisabled={isViewMode}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
} from '@mui/material';
import { ChangeEvent, useEffect, useState } from 'react';
import {
ComboBox,
CustomButton,
CustomModal,
CustomTextField,
Expand All @@ -21,11 +20,10 @@ import {
Color,
Severity,
TextFieldTypes,
TextFieldVariant,
Variant,
} from 'shared/enums';
import { useDialog } from 'shared/hooks';
import { DateUtils, InputFieldUtils } from 'shared/utils';
import { InputFieldUtils } from 'shared/utils';

import { EnrollmentHistoryModal } from 'components/clerkEnrollment/appointment/EnrollmentHistoryModal';
import { EnrollmentSkillsListTable } from 'components/clerkEnrollment/appointment/EnrollmentSkillsListTable';
Expand All @@ -46,7 +44,6 @@ import {
} from 'interfaces/clerkEnrollment';
import { ClerkEnrollmentTextFieldProps } from 'interfaces/clerkEnrollmentTextField';
import { PartialExamsAndSkills } from 'interfaces/common/enrollment';
import { ExaminerExamEvent } from 'interfaces/examinerExamEvent';
import { sendClerkEnrollmentAppointmentAuthLink } from 'redux/reducers/clerkEnrollmentAppointment';
import { clerkEnrollmentAppointmentSelector } from 'redux/selectors/clerkEnrollmentAppointment';
import { DateTimeUtils } from 'utils/dateTime';
Expand Down Expand Up @@ -322,33 +319,9 @@ const ClerkEnrollmentSkillsListFields = ({
);
};

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;
};

const ExamAndEnrollmentDetailsSection = ({
enrollment,
isViewMode,
examEvents,
newExamEvent,
onExamEventChange,
onCheckboxFieldChange,
editDisabled,
openGradeModal,
Expand All @@ -357,9 +330,6 @@ const ExamAndEnrollmentDetailsSection = ({
}: {
enrollment: ClerkEnrollmentAppointment;
isViewMode: boolean;
examEvents: Array<ExaminerExamEvent>;
newExamEvent: ExaminerExamEvent | undefined;
onExamEventChange: (value?: string) => void;
onCheckboxFieldChange: (
field:
| keyof PartialExamsAndSkills
Expand All @@ -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 (
<>
<div className="columns margin-top-lg space-between">
<H2>Tutkinnon tiedot</H2>
</div>
{isViewMode ? (
enrollment.examEvent && (
<div className="rows">
<H3>Tutkinnon kieli, aika ja paikka</H3>
<Text>
{translateCommon(`examLanguage.${enrollment.examEvent.language}`)}
{', '}
{DateTimeUtils.renderDate(enrollment.examEvent.date)}
{', '}
{translateMunicipality(enrollment.examEvent.municipality.code)}
{', '}
{enrollment.examEvent.location}
</Text>
</div>
)
) : (
<div className="half-max-width">
<ComboBox
autoHighlight
label={'Tutkinto'}
values={[...examEvents]
.map(examEventToOption)
.sort((a, b) => a.label.localeCompare(b.label))}
value={newExamEvent ? examEventToOption(newExamEvent) : null}
variant={TextFieldVariant.Outlined}
onChange={onExamEventChange}
/>
{enrollment.examEvent && (
<div className="rows">
<H3>Tutkinnon kieli, aika ja paikka</H3>
<Text>
{translateCommon(`examLanguage.${enrollment.examEvent.language}`)}
{', '}
{DateTimeUtils.renderDate(enrollment.examEvent.date)}
{', '}
{translateMunicipality(enrollment.examEvent.municipality.code)}
{', '}
{enrollment.examEvent.location}
</Text>
</div>
)}
{isViewMode ? (
Expand Down Expand Up @@ -663,9 +612,6 @@ const PaymentLinkModal = ({

export const ClerkEnrollmentAppointmentDetailsFields = ({
enrollment,
examEvents,
newExamEvent,
onExamEventChange,
editDisabled,
isViewMode,
oid,
Expand All @@ -675,14 +621,11 @@ export const ClerkEnrollmentAppointmentDetailsFields = ({
showFieldErrorBeforeChange,
}: {
enrollment: ClerkEnrollmentAppointment;
examEvents: Array<ExaminerExamEvent>;
newExamEvent: ExaminerExamEvent | undefined;
editDisabled: boolean;
isViewMode: boolean;
oid: string;
topControlButtons: JSX.Element;
showFieldErrorBeforeChange: boolean;
onExamEventChange: (value?: string) => void;
onTextFieldChange: (
field: ClerkEnrollmentTextFieldEnum,
) => (event: ChangeEvent<HTMLTextAreaElement>) => void;
Expand Down Expand Up @@ -816,10 +759,7 @@ export const ClerkEnrollmentAppointmentDetailsFields = ({
<Divider className="margin-top-lg" />
<ExamAndEnrollmentDetailsSection
enrollment={enrollment}
examEvents={examEvents}
isViewMode={isViewMode}
newExamEvent={newExamEvent}
onExamEventChange={onExamEventChange}
onCheckboxFieldChange={onCheckboxFieldChange}
editDisabled={editDisabled}
openGradeModal={() => setGradeModalOpen(true)}
Expand Down
28 changes: 28 additions & 0 deletions frontend/packages/vkt/src/hooks/useExamEventDescription.ts
Original file line number Diff line number Diff line change
@@ -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;
};
Loading

0 comments on commit 5ca29c6

Please sign in to comment.