Skip to content

Commit

Permalink
VKT(Frontend & Backend): Enrollment appointment clerk interface
Browse files Browse the repository at this point in the history
  • Loading branch information
jrkkp committed Oct 29, 2024
1 parent 715fdd7 commit bb20fb4
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ public ClerkEnrollmentAppointmentDTO getEnrollmentAppointment(@PathVariable fina
return clerkEnrollmentService.getEnrollmentAppointment(enrollmentAppointmentId);
}

@PutMapping(path = "/appointment/{enrollmentAppointmentId:\\d+}")
@Operation(tags = TAG_ENROLLMENT, summary = "Update enrollment appointment")
public ClerkEnrollmentDTO updateEnrollmentAppointment(@RequestBody @Valid final ClerkEnrollmentUpdateDTO dto) {
return clerkEnrollmentService.update(dto);
}

@GetMapping(path = "/attachment", consumes = ALL_VALUE)
@Operation(tags = TAG_ENROLLMENT, summary = "Download enrollment attachment")
public void attachmentRedirect(final HttpServletResponse response, @RequestParam final String key)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { ChangeEvent, useCallback, useEffect, useState } from 'react';
import { CustomButton, CustomModal } from 'shared/components';
import { CustomButton } from 'shared/components';
import { APIResponseStatus, Color, Severity, Variant } from 'shared/enums';
import { useDialog, useToast } from 'shared/hooks';
import { StringUtils } from 'shared/utils';

import { ClerkEnrollmentAppointmentDetailsFields } from 'components/clerkEnrollment/appointment/ClerkEnrollmentAppointmentDetailsFields';
import { ControlButtons } from 'components/clerkEnrollment/overview/ControlButtons';
import { MoveModal } from 'components/clerkEnrollment/overview/MoveModal';
import { useClerkTranslation, useCommonTranslation } from 'configs/i18n';
import { useAppDispatch, useAppSelector } from 'configs/redux';
import { EnrollmentStatus, UIMode } from 'enums/app';
Expand All @@ -16,8 +15,8 @@ import { ClerkEnrollmentAppointment } from 'interfaces/clerkEnrollment';
import { PartialExamsAndSkills } from 'interfaces/common/enrollment';
import {
resetClerkEnrollmentDetailsUpdate,
updateClerkEnrollmentDetails,
} from 'redux/reducers/clerkEnrollmentDetails';
updateClerkEnrollmentAppointment,
} from 'redux/reducers/clerkEnrollmentAppointment';
import {
changeClerkEnrollmentStatus,
resetClerkEnrollmentStatusChange,
Expand Down Expand Up @@ -47,14 +46,10 @@ export const ClerkEnrollmentAppointmentDetails = ({
const [enrollmentDetails, setEnrollmentDetails] = useState<
ClerkEnrollmentAppointment | undefined
>(enrollment);
const [isMoveModalOpen, setIsOpenModalOpen] = useState(false);
const [hasLocalChanges, setHasLocalChanges] = useState(false);
const [currentUIMode, setCurrentUIMode] = useState(UIMode.View);
const isViewMode = currentUIMode === UIMode.View;

const handleMoveButtonCLick = () => setIsOpenModalOpen(true);
const closeMoveModal = () => setIsOpenModalOpen(false);

const resetLocalEnrollmentDetails = useCallback(() => {
setEnrollmentDetails(enrollment);
}, [enrollment]);
Expand Down Expand Up @@ -140,43 +135,30 @@ export const ClerkEnrollmentAppointmentDetails = ({
return undefined;
}

let updatedEnrollmentDetails;
if (
field === ClerkEnrollmentTextFieldEnum.FirstName ||
field === ClerkEnrollmentTextFieldEnum.LastName
) {
updatedEnrollmentDetails = {
...prevState,
person: {
...prevState.person,
[field]: fieldValue,
},
};
} else {
updatedEnrollmentDetails = {
...prevState,
[field]: fieldValue,
};
}

return updatedEnrollmentDetails;
return {
...prevState,
[field]: fieldValue,
};
});
};

const handleSaveButtonClick = () => {
dispatch(
updateClerkEnrollmentDetails({
updateClerkEnrollmentAppointment({
enrollment: {
...enrollmentDetails,
understandingSkill:
enrollmentDetails.speechComprehensionPartialExam &&
enrollmentDetails.readingComprehensionPartialExam,
},
examEvent,
}),
);
};

const handleMoveButtonClick = () => {
// TODO
};

const handleEditButtonClick = () => {
resetLocalEnrollmentDetails();
setCurrentUIMode(UIMode.Edit);
Expand Down Expand Up @@ -237,15 +219,6 @@ export const ClerkEnrollmentAppointmentDetails = ({

return (
<>
<CustomModal
data-testid="clerk-enrollment-details__move-modal"
open={isMoveModalOpen}
onCloseModal={closeMoveModal}
aria-labelledby="modal-title"
modalTitle={t('moveModal.title')}
>
<MoveModal enrollment={enrollmentDetails} onCancel={closeMoveModal} />
</CustomModal>
<ClerkEnrollmentAppointmentDetailsFields
showFieldErrorBeforeChange={false}
enrollment={enrollmentDetails}
Expand All @@ -257,7 +230,7 @@ export const ClerkEnrollmentAppointmentDetails = ({
onCancel={handleCancelButtonClick}
onEdit={handleEditButtonClick}
onSave={handleSaveButtonClick}
onMove={handleMoveButtonCLick}
onMove={handleMoveButtonClick}
isViewMode={isViewMode}
hasRequiredDetails={hasRequiredDetails}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
import { useDialog } from 'shared/hooks';
import { InputFieldUtils } from 'shared/utils';

import { ExamEventDetails } from 'components/publicEnrollment/steps/ExamEventDetails';
import {
translateOutsideComponent,
useClerkTranslation,
Expand Down Expand Up @@ -330,8 +329,6 @@ export const ClerkEnrollmentAppointmentDetailsFields = ({
const displayPaymentHistory = enrollment.payments.length > 1;

// TODO Remove this flag once digital certificates are available
const isDigitalCertificateAvailable = false;

return (
<div className="clerk-enrollment-details-fields">
<div className="columns margin-top-lg space-between">
Expand Down Expand Up @@ -375,6 +372,39 @@ export const ClerkEnrollmentAppointmentDetailsFields = ({
)}
/>
</div>
{!enrollment.digitalCertificateConsent && (
<div className="rows gapped margin-top-lg">
<H3>
{translateCommon('enrollment.certificateShipping.addressTitle')}
</H3>
<div className="grid-columns gapped">
<ClerkEnrollmentDetailsTextField
{...getCommonTextFieldProps(
ClerkEnrollmentTextFieldEnum.Street,
editDisabled,
)}
/>
<ClerkEnrollmentDetailsTextField
{...getCommonTextFieldProps(
ClerkEnrollmentTextFieldEnum.PostalCode,
editDisabled,
)}
/>
<ClerkEnrollmentDetailsTextField
{...getCommonTextFieldProps(
ClerkEnrollmentTextFieldEnum.Town,
editDisabled,
)}
/>
<ClerkEnrollmentDetailsTextField
{...getCommonTextFieldProps(
ClerkEnrollmentTextFieldEnum.Country,
editDisabled,
)}
/>
</div>
</div>
)}
<div className="margin-top-sm">
<H3>{t('header.previousEnrollment')}</H3>
</div>
Expand Down Expand Up @@ -461,7 +491,6 @@ export const ClerkEnrollmentAppointmentDetailsFields = ({
</div>
</div>
)}
<ExamEventDetails enrollment={enrollment} clerkView={true} />
<div className="rows gapped-sm margin-top-lg">
<H3>{t('status')}</H3>
<Text>{t(`enrollmentStatus.${enrollment.status}`)}</Text>
Expand Down Expand Up @@ -501,63 +530,6 @@ export const ClerkEnrollmentAppointmentDetailsFields = ({
)}
</div>
)}
{isDigitalCertificateAvailable && (
<div className="rows gapped-sm margin-top-lg">
<H3>{t('header.digitalCertificateConsent')}</H3>
<FormControlLabel
className="clerk-enrollment-details-fields__certificate-shipping__consent"
control={
<Checkbox
data-testid="clerk-enrollment__details-fields__digitalCertificateConsent"
onClick={() =>
onCheckboxFieldChange(
'digitalCertificateConsent',
!enrollment.digitalCertificateConsent,
)
}
color={Color.Secondary}
checked={enrollment.digitalCertificateConsent}
disabled={editDisabled}
/>
}
label={translateCommon('enrollment.certificateShipping.consent')}
/>
</div>
)}

{!enrollment.digitalCertificateConsent && (
<div className="rows gapped margin-top-lg">
<H3>
{translateCommon('enrollment.certificateShipping.addressTitle')}
</H3>
<div className="grid-columns gapped">
<ClerkEnrollmentDetailsTextField
{...getCommonTextFieldProps(
ClerkEnrollmentTextFieldEnum.Street,
editDisabled,
)}
/>
<ClerkEnrollmentDetailsTextField
{...getCommonTextFieldProps(
ClerkEnrollmentTextFieldEnum.PostalCode,
editDisabled,
)}
/>
<ClerkEnrollmentDetailsTextField
{...getCommonTextFieldProps(
ClerkEnrollmentTextFieldEnum.Town,
editDisabled,
)}
/>
<ClerkEnrollmentDetailsTextField
{...getCommonTextFieldProps(
ClerkEnrollmentTextFieldEnum.Country,
editDisabled,
)}
/>
</div>
</div>
)}
</div>
<CustomModal
open={paymentLinkModalOpen}
Expand Down
3 changes: 2 additions & 1 deletion frontend/packages/vkt/src/interfaces/clerkEnrollment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export interface ClerkEnrollmentAppointment extends ClerkEnrollmentContact {
}

export interface ClerkEnrollmentAppointmentResponse
extends Omit<ClerkEnrollmentAppointment, 'enrollmentTime'> {
extends Omit<ClerkEnrollmentAppointment, 'enrollmentTime' | 'payments'> {
enrollmentTime: string;
payments: Array<ClerkPaymentResponse>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export const ClerkEnrollmentAppointmentOverviewPage: FC = () => {
}
}, [dispatch, status, params.enrollmentAppointmentId]);

console.log('enrollment', enrollment);
return (
<Box className="clerk-enrollment-overview-page">
<H1 data-testid="clerk-enrollment-overview-page__header"></H1>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { APIResponseStatus } from 'shared/enums';

import { ClerkEnrollmentAppointment } from 'interfaces/clerkEnrollment';
import { ClerkExamEvent } from 'interfaces/clerkExamEvent';

interface ClerkEnrollmentAppointmentState {
status: APIResponseStatus;
Expand All @@ -28,16 +29,38 @@ const clerkEnrollmentAppointmentSlice = createSlice({
state.enrollment = action.payload;
state.status = APIResponseStatus.Success;
},
storeClerkEnrollmentAppointmentUpdate(
state,
action: PayloadAction<ClerkEnrollmentAppointment>,
) {
state.status = APIResponseStatus.Success;
state.enrollment = action.payload;
},
rejectClerkEnrollmentAppointment(state) {
state.status = APIResponseStatus.Error;
},
updateClerkEnrollmentAppointment(
state,
_action: PayloadAction<{
enrollment: ClerkEnrollmentAppointment;
examEvent?: ClerkExamEvent;
}>,
) {
state.status = APIResponseStatus.InProgress;
},
resetClerkEnrollmentDetailsUpdate(state) {
state.status = initialState.status;
},
},
});

export const clerkEnrollmentAppointmentReducer =
clerkEnrollmentAppointmentSlice.reducer;
export const {
storeClerkEnrollmentAppointmentUpdate,
rejectClerkEnrollmentAppointment,
storeClerkEnrollmentAppointment,
loadClerkEnrollmentAppointment,
updateClerkEnrollmentAppointment,
resetClerkEnrollmentDetailsUpdate,
} = clerkEnrollmentAppointmentSlice.actions;
Original file line number Diff line number Diff line change
@@ -1,17 +1,52 @@
import { PayloadAction } from '@reduxjs/toolkit';
import { AxiosResponse } from 'axios';
import { AxiosError, AxiosResponse } from 'axios';
import { call, put, takeLatest } from 'redux-saga/effects';

import axiosInstance from 'configs/axios';
import { APIEndpoints } from 'enums/api';
import { ClerkEnrollmentAppointmentResponse } from 'interfaces/clerkEnrollment';
import {
ClerkEnrollmentAppointment,
ClerkEnrollmentAppointmentResponse,
} from 'interfaces/clerkEnrollment';
import { setAPIError } from 'redux/reducers/APIError';
import {
loadClerkEnrollmentAppointment,
rejectClerkEnrollmentAppointment,
storeClerkEnrollmentAppointment,
storeClerkEnrollmentAppointmentUpdate,
updateClerkEnrollmentAppointment,
} from 'redux/reducers/clerkEnrollmentAppointment';
import { NotifierUtils } from 'utils/notifier';
import { SerializationUtils } from 'utils/serialization';

function* updateClerkEnrollmentAppointmentSaga(
action: PayloadAction<{
enrollment: ClerkEnrollmentAppointment;
}>,
) {
const { enrollment } = action.payload;

try {
const apiResponse: AxiosResponse<ClerkEnrollmentAppointmentResponse> =
yield call(
axiosInstance.put,
APIEndpoints.ClerkEnrollment,
SerializationUtils.serializeClerkEnrollmentAppointment(enrollment),
);
const updatedEnrollment =
SerializationUtils.deserializeClerkEnrollmentAppointment(
apiResponse.data,
);

yield put(storeClerkEnrollmentAppointmentUpdate(updatedEnrollment));
//yield put(storeClerkExamEventOverview(updatedExamEvent));
} catch (error) {
const errorMessage = NotifierUtils.getAPIErrorMessage(error as AxiosError);
yield put(setAPIError(errorMessage));
//yield put(rejectClerkEnrollmentDetailsUpdate());
}
}

function* loadClerkEnrollmentAppointmentSaga(action: PayloadAction<number>) {
try {
const appointmentId = action.payload;
Expand All @@ -30,6 +65,10 @@ function* loadClerkEnrollmentAppointmentSaga(action: PayloadAction<number>) {
}

export function* watchClerkEnrollmentAppointment() {
yield takeLatest(
updateClerkEnrollmentAppointment.type,
updateClerkEnrollmentAppointmentSaga,
);
yield takeLatest(
loadClerkEnrollmentAppointment.type,
loadClerkEnrollmentAppointmentSaga,
Expand Down
Loading

0 comments on commit bb20fb4

Please sign in to comment.