Skip to content

Commit

Permalink
Updated as per changes requested
Browse files Browse the repository at this point in the history
  • Loading branch information
shivankacker committed Aug 30, 2024
1 parent bda3f65 commit 4bf5708
Show file tree
Hide file tree
Showing 10 changed files with 403 additions and 108 deletions.
16 changes: 15 additions & 1 deletion src/Common/constants.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { IConfig } from "./hooks/useConfig";
import { PatientCategory } from "../Components/Facility/models";
import {
PatientCategory,
SpokeRelationship,
} from "../Components/Facility/models";
import { SortOption } from "../Components/Common/SortDropdown";
import { dateQueryString } from "../Utils/utils";
import { IconName } from "../CAREUI/icons/CareIcon";
Expand Down Expand Up @@ -1466,6 +1469,17 @@ export const DEFAULT_ALLOWED_EXTENSIONS = [
"application/vnd.oasis.opendocument.spreadsheet,application/pdf",
];

export const SPOKE_RELATION_TYPES = [
{
text: "Regular",
value: SpokeRelationship.REGULAR,
},
{
text: "Tele ICU",
value: SpokeRelationship.TELE_ICU,
},
];

export const HumanBodyPaths = {
anterior: [
{
Expand Down
6 changes: 6 additions & 0 deletions src/Components/Common/FacilitySelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ interface FacilitySelectProps {
selected?: FacilityModel | FacilityModel[] | null;
setSelected: (selected: FacilityModel | FacilityModel[] | null) => void;
allowNone?: boolean;
placeholder?: string;
filter?: (facilities: FacilityModel) => boolean;
}

export const FacilitySelect = (props: FacilitySelectProps) => {
Expand All @@ -44,6 +46,8 @@ export const FacilitySelect = (props: FacilitySelectProps) => {
allowNone = false,
freeText = false,
errors = "",
placeholder,
filter,
} = props;

const facilitySearch = useCallback(
Expand Down Expand Up @@ -82,6 +86,7 @@ export const FacilitySelect = (props: FacilitySelectProps) => {

return (
<AutoCompleteAsync
placeholder={placeholder}
name={name}
required={required}
multiple={multiple}
Expand All @@ -97,6 +102,7 @@ export const FacilitySelect = (props: FacilitySelectProps) => {
compareBy="id"
className={className}
error={errors}
filter={filter}
/>
);
};
29 changes: 29 additions & 0 deletions src/Components/Facility/FacilityBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import CareIcon from "../../CAREUI/icons/CareIcon";
import { FacilityModel } from "./models";

export default function FacilityBlock(props: { facility: FacilityModel }) {
const { facility } = props;

return (
<div className="flex items-center gap-4">
<div className="flex aspect-square h-14 items-center justify-center overflow-hidden rounded-lg border border-gray-400 bg-gray-200">
{facility.read_cover_image_url ? (
<img
className="h-full w-full object-cover"
src={facility.read_cover_image_url}
/>
) : (
<>
<CareIcon icon="l-hospital" />
</>
)}
</div>
<div>
<b className="font-semibold">{facility.name}</b>
<p className="text-sm">
{facility.address} {facility.local_body_object?.name}
</p>
</div>
</div>
);
}
85 changes: 10 additions & 75 deletions src/Components/Facility/FacilityCreate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import routes from "../../Redux/api.js";
import useQuery from "../../Utils/request/useQuery.js";
import { RequestResult } from "../../Utils/request/types.js";
import useAuthUser from "../../Common/hooks/useAuthUser";
import SpokeFacilityEditor from "./SpokeFacilityEditor.js";

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

Expand Down Expand Up @@ -161,7 +162,6 @@ export const FacilityCreate = (props: FacilityProps) => {
const [stateId, setStateId] = useState<number>();
const [districtId, setDistrictId] = useState<number>();
const [localBodyId, setLocalBodyId] = useState<number>();
const [hubFacilities, setHubFacilities] = useState<string[]>([]);
const { goBack } = useAppHistory();
const headerText = !facilityId ? "Create Facility" : "Update Facility";
const buttonText = !facilityId ? "Save Facility" : "Update Facility";
Expand Down Expand Up @@ -249,48 +249,7 @@ export const FacilityCreate = (props: FacilityProps) => {
},
);

const facilitiesQuery = useQuery(routes.getAllFacilities);
const hubsQuery = useQuery(routes.getFacilityHubs, {
pathParams: {
id: facilityId!,
},
prefetch: !!facilityId,
onResponse: (res) => {
setHubFacilities(
res.data?.results.map((d) => d.hub_object.id) as string[],
);
},
});
const createHub = async (hubFacilityId: string) =>
await request(routes.createFacilityHub, {
body: {
hub: hubFacilityId,
},
pathParams: {
id: facilityId || "",
},
onResponse: ({ res }) => {
if (res?.ok) {
hubsQuery.refetch();
}
},
});
const deleteHub = async (hubFacilityId: string) =>
await request(routes.deleteFacilityHub, {
pathParams: {
id: facilityId || "",
hub_id: hubFacilityId,
},
onResponse: ({ res }) => {
if (res?.ok) {
hubsQuery.refetch();
}
},
});

const { data: facilities } = facilitiesQuery;

useQuery(routes.getPermittedFacility, {
const facilityQuery = useQuery(routes.getPermittedFacility, {
pathParams: {
id: facilityId!,
},
Expand Down Expand Up @@ -891,38 +850,14 @@ export const FacilityCreate = (props: FacilityProps) => {
required
types={["mobile", "landline"]}
/>
{facilityId && (
<MultiSelectFormField
{...field("hubs")}
placeholder={t("hubs")}
className={facilitiesQuery.loading ? "animate-pulse" : ""}
disabled={facilitiesQuery.loading || hubsQuery.loading}
options={
facilities?.results.filter(
(f) => f.id !== facilityId,
) || []
}
optionLabel={(o) => o.name}
optionValue={(o) => o.id}
value={hubFacilities}
onChange={async (event) => {
if (event.value.length > hubFacilities.length) {
createHub(event.value[event.value.length - 1] || "");
} else if (event.value.length < hubFacilities.length) {
deleteHub(
hubsQuery.data?.results.find(
(r) =>
r.hub_object.id ===
(hubFacilities.find(
(x) => !event.value.includes(x),
) || ""),
)?.id || "",
);
}
setHubFacilities(event.value as string[]);
}}
/>
)}
<div className="py-4 md:col-span-2">
<h4 className="mb-4">Spoke Facilities</h4>
{facilityId && (
<SpokeFacilityEditor
facility={{ ...facilityQuery.data, id: facilityId }}
/>
)}
</div>
<div className="grid grid-cols-1 gap-4 py-4 sm:grid-cols-2 md:col-span-2 xl:grid-cols-4">
<TextFormField
{...field("oxygen_capacity")}
Expand Down
152 changes: 152 additions & 0 deletions src/Components/Facility/SpokeFacilityEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
//import { useTranslation } from "react-i18next";
import routes from "../../Redux/api";
import request from "../../Utils/request/request";
import useQuery from "../../Utils/request/useQuery";
import { SelectFormField } from "../Form/FormFields/SelectFormField";
import {
FacilityModel,
FacilitySpokeErrors,
FacilitySpokeModel,
FacilitySpokeRequest,
SpokeRelationship,
} from "./models";
import ModelCrudEditor from "../Form/ModelCrudEditor";
import { FacilitySelect } from "../Common/FacilitySelect";
import { useEffect, useState } from "react";
import { SPOKE_RELATION_TYPES } from "../../Common/constants";
import FacilityBlock from "./FacilityBlock";

export interface SpokeFacilityEditorProps {
facility: Omit<FacilityModel, "id"> & { id: string };
}

export default function SpokeFacilityEditor(props: SpokeFacilityEditorProps) {
const { facility } = props;

//const { t } = useTranslation();

const spokesQuery = useQuery(routes.getFacilitySpokes, {
pathParams: {
id: facility.id,
},
});

const spokes = spokesQuery.data?.results;

const createSpoke = (body: FacilitySpokeRequest) =>
request(routes.createFacilitySpoke, {
body,
pathParams: {
id: facility.id,
},
onResponse: ({ res }) => {
if (res?.ok) {
spokesQuery.refetch();
}
},
});

const deleteSpoke = (spokeFacilityId: string) =>
request(routes.deleteFacilitySpoke, {
pathParams: {
id: facility.id,
spoke_id: spokeFacilityId,
},
onResponse: ({ res }) => {
if (res?.ok) {
spokesQuery.refetch();
}
},
});

const updateSpoke = (spokeFacilityId: string, body: FacilitySpokeRequest) =>
request(routes.updateFacilitySpokes, {
pathParams: {
id: facility.id,
spoke_id: spokeFacilityId,
},
body,
onResponse: ({ res }) => {
if (res?.ok) {
spokesQuery.refetch();
}
},
});

const FormRender = (
item: FacilitySpokeModel | FacilitySpokeRequest,
setItem: (item: FacilitySpokeModel | FacilitySpokeRequest) => void,
processing: boolean,
) => {
const [selectedFacility, setSelectedFacility] = useState<FacilityModel>();

useEffect(() => {
setItem({ ...item, spoke: selectedFacility?.id });
}, [selectedFacility]);

return (
<>
{"id" in item ? (
<div className="w-full">
<FacilityBlock facility={item.spoke_object} />
</div>
) : (
<FacilitySelect
multiple={false}
name="facility"
placeholder="Add Spoke Facility"
showAll={false}
showNOptions={8}
selected={selectedFacility}
setSelected={(v) =>
v && !Array.isArray(v) && setSelectedFacility(v)
}
errors=""
className="w-full"
disabled={processing}
filter={(f) =>
!!f.id &&
!spokes?.flatMap((s) => s.spoke_object.id).includes(f.id)
}
/>
)}
<SelectFormField
name="relationship_type"
options={SPOKE_RELATION_TYPES}
optionLabel={(v) => v.text}
optionValue={(v) => v.value}
value={item.relationship}
onChange={(v) => setItem({ ...item, relationship: v.value })}
errorClassName="hidden"
className="shrink-0"
disabled={processing}
/>
</>
);
};

return (
<>
<ModelCrudEditor<
FacilitySpokeModel,
FacilitySpokeRequest,
FacilitySpokeErrors
>
items={spokes}
onCreate={createSpoke}
onUpdate={updateSpoke}
onDelete={deleteSpoke}
loading={spokesQuery.loading}
errors={{}}
emptyText={"No Spokes"}
empty={{
spoke: "",
relationship: SpokeRelationship.REGULAR,
}}
createText="Add Spoke"
>
{FormRender}
</ModelCrudEditor>
</>
);
}
Loading

0 comments on commit 4bf5708

Please sign in to comment.