Skip to content

Commit

Permalink
fix(location): added duty staff section
Browse files Browse the repository at this point in the history
  • Loading branch information
aeswibon authored and Abhiuday committed Nov 27, 2023
1 parent c37b554 commit bc13cad
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 92 deletions.
6 changes: 6 additions & 0 deletions src/Components/Assets/AssetTypes.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BedModel } from "../Facility/models";
import { PerformedByModel } from "../HCX/misc";
import { PatientModel } from "../Patient/models";
import { UserAssignedModel } from "../Users/models";

export interface AssetLocationObject {
id: string;
Expand All @@ -14,6 +15,11 @@ export interface AssetLocationObject {
};
}

export interface AssetLocationDutyStaffObject {
duty_staff_objects: UserAssignedModel[];
duty_staff: number;
}

export enum AssetType {
NONE = "NONE",
INTERNAL = "INTERNAL",
Expand Down
151 changes: 125 additions & 26 deletions src/Components/Facility/AddLocationForm.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { useState, useEffect, lazy, SyntheticEvent } from "react";
import { navigate } from "raviger";
import { SyntheticEvent, lazy, useEffect, useState } from "react";
import { useDispatch } from "react-redux";
import {
createFacilityAssetLocation,
createFacilityAssetLocationDutyStaff,
getAnyFacility,
getFacilityAssetLocation,
getFacilityUsers,
updateFacilityAssetLocation,
} from "../../Redux/actions";
import * as Notification from "../../Utils/Notifications.js";
import { navigate } from "raviger";
import { Submit, Cancel } from "../Common/components/ButtonV2";
import TextFormField from "../Form/FormFields/TextFormField";
import TextAreaFormField from "../Form/FormFields/TextAreaFormField";
import { Cancel, Submit } from "../Common/components/ButtonV2";
import Page from "../Common/components/Page";
import { MultiSelectFormField } from "../Form/FormFields/SelectFormField";
import TextAreaFormField from "../Form/FormFields/TextAreaFormField";
import TextFormField from "../Form/FormFields/TextFormField";
import { UserAssignedModel } from "../Users/models";

const Loading = lazy(() => import("../Common/Loading"));

Expand All @@ -29,10 +33,20 @@ export const AddLocationForm = (props: LocationFormProps) => {
const [description, setDescription] = useState("");
const [facilityName, setFacilityName] = useState("");
const [locationName, setLocationName] = useState("");
const [errors, setErrors] = useState<any>({
const [doctorList, setDoctorList] = useState<UserAssignedModel[]>([]);
const [staffList, setStaffList] = useState<UserAssignedModel[]>([]);
const [doctors, setDoctors] = useState<UserAssignedModel[]>([]);
const [staff, setStaff] = useState<UserAssignedModel[]>([]);
const [errors, setErrors] = useState<{
name: string;
description: string;
middlewareAddress: string;
duty_staff: string;
}>({
name: "",
description: "",
middlewareAddress: "",
duty_staff: "",
});
const headerText = !locationId ? "Add Location" : "Update Location";
const buttonText = !locationId ? "Add Location" : "Update Location";
Expand All @@ -41,9 +55,22 @@ export const AddLocationForm = (props: LocationFormProps) => {
async function fetchFacilityName() {
setIsLoading(true);
if (facilityId) {
const res = await dispatchAction(getAnyFacility(facilityId));

setFacilityName(res?.data?.name || "");
const facility = await dispatchAction(getAnyFacility(facilityId));
const doctor = await dispatchAction(
getFacilityUsers(facilityId, {
user_type: "Doctor",
home_facility: facilityId,
})
);
const staff = await dispatchAction(
getFacilityUsers(facilityId, {
user_type: "Staff",
home_facility: facilityId,
})
);
setFacilityName(facility?.data?.name || "");
setDoctorList(doctor?.data?.results || []);
setStaffList(staff?.data?.results || []);
}
if (locationId) {
const res = await dispatchAction(
Expand All @@ -54,6 +81,16 @@ export const AddLocationForm = (props: LocationFormProps) => {
setLocationName(res?.data?.name || "");
setDescription(res?.data?.description || "");
setMiddlewareAddress(res?.data?.middleware_address || "");
setDoctors(
res?.data?.duty_staff_objects
.filter((doc: UserAssignedModel) => doc.user_type === "Doctor")
.map((doc: UserAssignedModel) => doc.id) || []
);
setStaff(
res?.data?.duty_staff_objects
.filter((s: UserAssignedModel) => s.user_type === "Staff")
.map((s: UserAssignedModel) => s.id) || []
);
}
setIsLoading(false);
}
Expand All @@ -66,6 +103,7 @@ export const AddLocationForm = (props: LocationFormProps) => {
name: "",
description: "",
middlewareAddress: "",
duty_staff: "",
};

if (name.trim().length === 0) {
Expand Down Expand Up @@ -108,24 +146,47 @@ export const AddLocationForm = (props: LocationFormProps) => {
setIsLoading(false);
if (res) {
if (res.status === 201 || res.status === 200) {
const notificationMessage = locationId
? "Location updated successfully"
: "Location created successfully";

navigate(`/facility/${facilityId}/location`, {
replace: true,
});
Notification.Success({
msg: notificationMessage,
});
} else if (res.status === 400) {
Object.keys(res.data).forEach((key) => {
setErrors((prevState: any) => ({
...prevState,
[key]: res.data[key],
}));
});
const duty_res = await dispatchAction(
createFacilityAssetLocationDutyStaff(
{
duty_staff: [...doctors, ...staff],
},
facilityId,
res.data.id
)
);
if (duty_res.status === 200) {
Notification.Success({
msg: "Duty Staff assigned successfully",
});

const notificationMessage = locationId
? "Location updated successfully"
: "Location created successfully";

Notification.Success({
msg: notificationMessage,
});

navigate(`/facility/${facilityId}/location`, {
replace: true,
});
} else if (duty_res.status === 400) {
Object.keys(duty_res.data).forEach((key) => {
setErrors((prevState) => ({
...prevState,
[key]: duty_res.data[key],
}));
});
}
}
} else if (res.status === 400) {
Object.keys(res.data).forEach((key) => {
setErrors((prevState) => ({
...prevState,
[key]: res.data[key],
}));
});
}
};

Expand All @@ -151,6 +212,12 @@ export const AddLocationForm = (props: LocationFormProps) => {
<div className="cui-card">
<form onSubmit={handleSubmit}>
<div className="mt-2 grid grid-cols-1 gap-4">
<div className="flex flex-row items-center">
<label className="text-lg font-bold text-gray-900">
General Details
</label>
<hr className="ml-6 flex-1 border border-gray-400" />
</div>
<div>
<TextFormField
name="name"
Expand Down Expand Up @@ -182,6 +249,38 @@ export const AddLocationForm = (props: LocationFormProps) => {
error={errors.middlewareAddress}
/>
</div>
<div className="flex flex-row items-center">
<label className="text-lg font-bold text-gray-900">
Duty Staff
</label>
<hr className="ml-6 flex-1 border border-gray-400" />
</div>
<div>
<MultiSelectFormField
name="doctors"
label="Doctors"
onChange={(e) => setDoctors(e.value)}
options={doctorList}
value={doctors}
optionLabel={(option: any) =>
`${option.first_name} ${option.last_name}`
}
optionValue={(option: any) => option.id}
/>
</div>
<div>
<MultiSelectFormField
name="staff"
label="Staff"
onChange={(e) => setStaff(e.value)}
options={staffList}
value={staff}
optionLabel={(option: any) =>
`${option.first_name} ${option.last_name}`
}
optionValue={(option: any) => option.id}
/>
</div>
</div>
<div className="cui-form-button-group mt-4">
<Cancel
Expand Down
105 changes: 63 additions & 42 deletions src/Components/Facility/LocationManagement.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { lazy } from "react";
import ButtonV2 from "../Common/components/ButtonV2";
import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor";
import { useTranslation } from "react-i18next";
import CareIcon from "../../CAREUI/icons/CareIcon";
import Page from "../Common/components/Page";
import routes from "../../Redux/api";
import PaginatedList from "../../CAREUI/misc/PaginatedList";
import routes from "../../Redux/api";
import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor";
import ButtonV2 from "../Common/components/ButtonV2";
import Page from "../Common/components/Page";
import { LocationModel } from "./models";

const Loading = lazy(() => import("../Common/Loading"));
Expand All @@ -14,14 +15,15 @@ interface Props {
}

export default function LocationManagement({ facilityId }: Props) {
const { t } = useTranslation();
return (
<PaginatedList
route={routes.listFacilityAssetLocation}
pathParams={{ facility_external_id: facilityId }}
>
{() => (
<Page
title="Location Management"
title={t("location_management")}
backUrl={`/facility/${facilityId}`}
options={
<ButtonV2
Expand All @@ -41,11 +43,11 @@ export default function LocationManagement({ facilityId }: Props) {
className="w-full lg:hidden"
>
<CareIcon icon="l-plus" className="text-lg" />
Add New Location
{t("add_new_location")}
</ButtonV2>
</div>
<PaginatedList.WhenEmpty className="flex w-full justify-center border-b border-gray-200 bg-white p-5 text-center text-2xl font-bold text-gray-500">
<span>No locations available</span>
<span>{t("no_locations_available")}</span>
</PaginatedList.WhenEmpty>

<PaginatedList.WhenLoading>
Expand All @@ -70,42 +72,61 @@ const Location = ({
description,
middleware_address,
id,
}: LocationModel) => (
<div className="w-full items-center justify-between rounded border border-gray-300 bg-white p-6 shadow-sm transition-all duration-200 ease-in-out hover:border-primary-400 lg:flex">
<div className="lg:w-3/4">
<div className="w-full items-baseline gap-4 lg:flex lg:items-center">
<p className="break-words text-xl lg:mr-4 lg:w-3/4">
{name}
<p className="break-all text-sm text-gray-700">
{description || "-"}
duty_staff_objects,
}: LocationModel) => {
const doctors =
duty_staff_objects?.filter((u) => u.user_type === "Doctor") || [];
const staffs =
duty_staff_objects?.filter((u) => u.user_type === "Staff") || [];

const { t } = useTranslation();
return (
<div className="w-full items-center justify-between rounded border border-gray-300 bg-white p-6 shadow-sm transition-all duration-200 ease-in-out hover:border-primary-400 lg:flex">
<div className="lg:w-3/4">
<div className="w-full items-baseline space-y-2 lg:flex lg:space-x-2">
<p className="break-words text-sm lg:mr-4 lg:w-1/6">{name}</p>
<p className="break-all text-sm lg:w-1/2">{description}</p>
<p className="break-all text-sm lg:w-1/2">{middleware_address}</p>
<p className="flex flex-col gap-y-2 text-sm lg:w-1/6">
{doctors.map((doctor) => (
<div className="flex w-full rounded-lg border border-primary-600 bg-primary-100 px-3 py-1 text-primary-900">
<CareIcon className="care-l-user-md" />
<div className="ml-3">{`${doctor.first_name} ${doctor.last_name}`}</div>
</div>
))}
</p>
</p>
<p className="break-all text-sm lg:mr-4 lg:w-3/4">
{middleware_address}
</p>
<p className="flex flex-col gap-y-2 text-sm lg:w-1/6">
{staffs.map((s) => (
<div className="flex w-full rounded-lg border border-primary-600 bg-primary-100 px-3 py-1 text-primary-900">
<CareIcon className="care-l-user-nurse" />
<div className="ml-3">{`${s.first_name} ${s.last_name}`}</div>
</div>
))}
</p>
</div>
</div>
</div>

<div className="mt-4 flex flex-col gap-2 lg:mt-0 lg:flex-row">
<ButtonV2
variant="secondary"
border
className="w-full lg:w-auto"
href={`location/${id}/update`}
authorizeFor={NonReadOnlyUsers}
>
<CareIcon className="care-l-pen text-lg" />
Edit
</ButtonV2>
<ButtonV2
variant="secondary"
border
className="w-full lg:w-auto"
href={`location/${id}/beds`}
>
<CareIcon className="care-l-bed text-lg" />
Manage Beds
</ButtonV2>
<div className="mt-4 flex flex-col gap-2 lg:mt-0 lg:flex-row">
<ButtonV2
variant="secondary"
border
className="w-full lg:w-auto"
href={`location/${id}/update`}
authorizeFor={NonReadOnlyUsers}
>
<CareIcon className="care-l-pen text-lg" />
{t("edit")}
</ButtonV2>
<ButtonV2
variant="secondary"
border
className="w-full lg:w-auto"
href={`location/${id}/beds`}
>
<CareIcon className="care-l-bed text-lg" />
{t("manage_beds")}
</ButtonV2>
</div>
</div>
</div>
);
);
};
Loading

0 comments on commit bc13cad

Please sign in to comment.