Skip to content

Commit

Permalink
update: Update exam form
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveGT96 committed Oct 16, 2024
1 parent 775474e commit 068c883
Show file tree
Hide file tree
Showing 12 changed files with 167 additions and 35 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,5 +148,8 @@
},
"_moduleAliases": {
"@": "./dist"
},
"volta": {
"node": "20.18.0"
}
}
25 changes: 19 additions & 6 deletions src/components/accessories/admin/exams/editExam/EditExam.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useAppDispatch, useAppSelector } from "libraries/hooks/redux";
import React from "react";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { Navigate, useLocation, useParams } from "react-router";
import { PATHS } from "../../../../../consts";
import { ExamDTO } from "../../../../../generated";
import { updateExam } from "../../../../../state/exams";
import { getExamRows, updateExam } from "../../../../../state/exams";
import ExamForm from "../examForm/ExamForm";
import { getInitialFields } from "../examForm/consts";

Expand All @@ -13,13 +13,26 @@ export const EditExam = () => {
const { t } = useTranslation();
const { state }: { state: ExamDTO | undefined } = useLocation();
const { id } = useParams();
const update = useAppSelector((state) => state.operations.update);
const update = useAppSelector((state) => state.exams.examUpdate);

const handleSubmit = (examDTO: ExamDTO) => {
const examRows: string[] | undefined = useAppSelector((state) =>
state.exams.examRowsByExamCode.data?.map((row) => row.description!)
);

useEffect(() => {
if (id) {
dispatch(getExamRows(id));
}
}, [dispatch, id]);

const handleSubmit = ({
rows,
...examDTO
}: ExamDTO & { rows: string[] | undefined }) => {
dispatch(
updateExam({
code: examDTO.code!!,
examWithRowsDTO: { exam: examDTO, rows: [] },
examWithRowsDTO: { exam: examDTO, rows },
})
);
};
Expand All @@ -35,7 +48,7 @@ export const EditExam = () => {
isLoading={!!update.isLoading}
resetButtonLabel={t("common.cancel")}
submitButtonLabel={t("exam.updateExam")}
fields={getInitialFields(state)}
fields={getInitialFields(state, examRows)}
/>
);
};
93 changes: 80 additions & 13 deletions src/components/accessories/admin/exams/examForm/ExamForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import React, {
} from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router";
import { number, object, string } from "yup";
import { array, number, object, string } from "yup";
import checkIcon from "../../../../../assets/check-icon.png";
import warningIcon from "../../../../../assets/warning-icon.png";
import { PATHS } from "../../../../../consts";
Expand All @@ -28,6 +28,8 @@ import TextField from "../../../textField/TextField";
import "./styles.scss";
import { IExamProps } from "./types";

import { AddCircle } from "@mui/icons-material";
import { IconButton } from "@mui/material";
import { useAppDispatch, useAppSelector } from "libraries/hooks/redux";
import AutocompleteField from "../../../autocompleteField/AutocompleteField";
import InfoBox from "../../../infoBox/InfoBox";
Expand Down Expand Up @@ -60,6 +62,15 @@ const ExamForm: FC<IExamProps> = ({
[examTypeState.data]
);

const procedureOptions = useMemo(
() => [
{ value: "1", label: t("exam.procedures.1") },
{ value: "2", label: t("exam.procedures.2") },
{ value: "3", label: t("exam.procedures.3") },
],
[t]
);

const errorMessage = useMemo(
() =>
(creationMode
Expand All @@ -79,6 +90,18 @@ const ExamForm: FC<IExamProps> = ({
code: string().required(t("common.required")),
description: string().required(t("common.required")),
examtype: string().required(t("common.required")),
rows: array()
.of(string().required(t("common.required")))
.test({
name: "min",
exclusive: true,
test: function (value) {
return parseInt(this.parent.procedure) === 3
? true
: (value as string[]).length <= 2;
},
message: t("exam.minLength"),
}),
procedure: number()
.test({
name: "onetwothree",
Expand Down Expand Up @@ -119,11 +142,34 @@ const ExamForm: FC<IExamProps> = ({
navigate(-1);
};

const addExamRow = useCallback(() => {
formik.setFieldValue("rows", [...formik.values.rows, ""]);
}, [formik]);

const removeExamRow = useCallback(
(index: number) => () => {
formik.setFieldValue(
"rows",
(formik.values.rows as string[]).splice(index, 1)
);
},
[formik]
);

const onBlurCallback = useCallback(
(fieldName: string) =>
(e: React.FocusEvent<HTMLDivElement>, value: string) => {
handleBlur(e);
setFieldValue(fieldName, value);
if (fieldName === "procedure") {
const rows = formik.values.rows as string[];
if (parseInt(value) === 3) {
setFieldValue("rows", []);
} else if (rows.length < 2) {
setFieldValue("rows", rows.length === 1 ? [rows[0], ""] : ["", ""]);
}
console.log(formik.values.rows);
}
},
[handleBlur, setFieldValue]
);
Expand Down Expand Up @@ -193,18 +239,7 @@ const ExamForm: FC<IExamProps> = ({
fieldName="selectedType"
fieldValue={formik.values.procedure}
label={t("exam.procedure")}
options={[
{
label: '1: a list of available "string" results',
value: "1",
},
{ label: '2: a list of all "boolean" results', value: "2" },
{
label:
"3: exact value (it will be typed in by the laboratorist)",
value: "3",
},
]}
options={procedureOptions}
errorText={getErrorText("procedure")}
isValid={isValid("procedure")}
onChange={(v) => formik.setFieldValue("procedure", v)}
Expand All @@ -226,6 +261,38 @@ const ExamForm: FC<IExamProps> = ({
</div>
</div>

{["1", "2"].includes(formik.values.procedure) && (
<div className="column start-sm center-xs exam-rows">
<div className="options_header">
<span className="title">Exam options</span>
{isValid("rows") && (
<span className="error">{getErrorText("rows")}</span>
)}
</div>
{(formik.values.rows as string[]).map((_, index) => (
<div className="examForm__item halfWidth" key={index}>
<TextField
field={formik.getFieldProps(`rows.${index}`)}
theme="regular"
label={""}
isValid={isValid(`rows.${index}`)}
errorText={getErrorText(`rows.${index}`)}
onBlur={formik.handleBlur}
type="text"
disabled={isLoading || !creationMode}
/>
</div>
))}
<IconButton
onClick={addExamRow}
className="add-row-icon"
size="medium"
>
<AddCircle />
</IconButton>
</div>
)}

<div className="examForm__buttonSet">
<div className="submit_button">
<Button
Expand Down
14 changes: 10 additions & 4 deletions src/components/accessories/admin/exams/examForm/consts.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { ExamDTO } from "../../../../../generated";
import { TFields } from "../../../../../libraries/formDataHandling/types";
import { ExamProps } from "../types";
import { ExamFormFieldName } from "../types";

export const getInitialFields: (
operation: ExamDTO | undefined
) => TFields<ExamProps> = (exam) => ({
exam: ExamDTO | undefined,
rows: string[] | undefined
) => TFields<ExamFormFieldName> = (exam, rows) => ({
code: { type: "text", value: exam?.code ?? "" },
examtype: { type: "text", value: exam?.examtype?.code ?? "" },
description: { type: "text", value: exam?.description ?? "" },
procedure: { type: "number", value: exam?.procedure?.toString() ?? "" },
procedure: { type: "number", value: exam?.procedure?.toString() ?? "3" },
defaultResult: { type: "text", value: exam?.defaultResult ?? "" },
lock: { type: "number", value: exam?.lock ?? "" },
rows: {
type: "text",
isArray: true,
value: JSON.stringify(rows ?? (exam?.procedure !== 3 ? ["", ""] : [])),
},
});
29 changes: 29 additions & 0 deletions src/components/accessories/admin/exams/examForm/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,35 @@
justify-content: space-between;
}

.column {
display: flex;
flex-direction: column;
}

.exam-rows {
.options_header {
padding: 16px;
width: 100%;
display: flex;
flex-direction: column;
.title {
font-size: x-large;
font-weight: lighter;
}

.error {
color: red;
font-size: x-small;
align-self: flex-start;
}
}
.add-row-icon {
margin-left: 16px;
width: 40px;
height: 40px;
}
}

.examForm__item {
margin: 7px 0px;
padding: 0px 15px;
Expand Down
6 changes: 3 additions & 3 deletions src/components/accessories/admin/exams/examForm/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ExamDTO } from "../../../../../generated";
import { TFields } from "../../../../../libraries/formDataHandling/types";
import { ExamProps } from "../types";
import { ExamFormFieldName } from "../types";

export interface IExamProps {
fields: TFields<ExamProps>;
onSubmit: (exam: ExamDTO) => void;
fields: TFields<ExamFormFieldName>;
onSubmit: (values: ExamDTO & { rows: string[] | undefined }) => void;
creationMode: boolean;
submitButtonLabel: string;
resetButtonLabel: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { deleteExamReset, getExams } from "../../../../../state/exams";
import { getExamTypes } from "../../../../../state/types/exams";
import InfoBox from "../../../infoBox/InfoBox";
import { TFilterField } from "../../../table/filter/types";
import { ExamProps } from "../types";
import { ExamFormFieldName } from "../types";

import checkIcon from "../../../../../assets/check-icon.png";
import ConfirmationDialog from "../../../confirmationDialog/ConfirmationDialog";
Expand All @@ -31,7 +31,7 @@ export const ExamsTable = ({ onDelete, onEdit, headerActions }: IOwnProps) => {
dispatch(getExamTypes());
}, [dispatch]);

const header: Array<ExamProps> = [
const header: Array<ExamFormFieldName> = [
"code",
"examtype",
"description",
Expand Down Expand Up @@ -64,7 +64,7 @@ export const ExamsTable = ({ onDelete, onEdit, headerActions }: IOwnProps) => {
procedure: t("exam.procedure"),
defaultResult: t("exam.defaultResult"),
};
const order: Array<ExamProps> = [
const order: Array<ExamFormFieldName> = [
"code",
"examtype",
"description",
Expand Down
9 changes: 6 additions & 3 deletions src/components/accessories/admin/exams/newExam/NewExam.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ export const NewExam = () => {
const { t } = useTranslation();
const create = useAppSelector((state) => state.exams.examCreate);

const handleSubmit = (value: ExamDTO) => {
dispatch(createExam({ examWithRowsDTO: { exam: value, rows: [] } }));
const handleSubmit = ({
rows,
...examDTO
}: ExamDTO & { rows: string[] | undefined }) => {
dispatch(createExam({ examWithRowsDTO: { exam: examDTO, rows } }));
};

return (
Expand All @@ -22,7 +25,7 @@ export const NewExam = () => {
isLoading={!!create.isLoading}
resetButtonLabel={t("common.cancel")}
submitButtonLabel={t("supplier.saveSupplier")}
fields={getInitialFields(undefined)}
fields={getInitialFields(undefined, undefined)}
/>
);
};
5 changes: 3 additions & 2 deletions src/components/accessories/admin/exams/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export type ExamProps =
export type ExamFormFieldName =
| "code"
| "examtype"
| "description"
| "procedure"
| "defaultResult";
| "defaultResult"
| "rows";
6 changes: 5 additions & 1 deletion src/libraries/formDataHandling/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ export const getFromFields = (
fieldAddress: TFieldAddress
): Record<string, any> => {
return Object.keys(fields).reduce((acc: Record<string, any>, key) => {
acc[key] = fields[key][fieldAddress];
if (fieldAddress === "value") {
acc[key] = fields[key].isArray
? JSON.parse(fields[key][fieldAddress])
: fields[key][fieldAddress];
}
return acc;
}, {});
};
Expand Down
1 change: 1 addition & 0 deletions src/libraries/formDataHandling/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface IFieldContent {
type: TFieldType;
isEnabled?: boolean;
isVisible?: boolean;
isArray?: boolean;
options?: Array<{ label: string; value: string }>;
}

Expand Down
5 changes: 5 additions & 0 deletions src/resources/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,11 @@
"examtype": "Exam Type",
"description": "Name",
"procedure": "Procedure",
"procedures": {
"1": "1 - Only one option",
"2": "2 - Multiple options can be selected",
"3": "3 - Custom value"
},
"defaultResult": "Default value",
"addExam": "New exam",
"editExam": "Edit exam",
Expand Down

0 comments on commit 068c883

Please sign in to comment.