Skip to content
Open
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e5182d5
fix: Overlapping buttons
navaspavil Jul 9, 2026
db46f8c
feat: implement drawer for displaying all supply deliveries when an i…
navaspavil Jul 9, 2026
b1084ff
Remove filter and update button
navaspavil Jul 9, 2026
58197a9
fix: update query key for supply deliveries and simplify drawer open …
navaspavil Jul 9, 2026
9bda067
fix: add button type attribute to clear selection button in ResourceD…
navaspavil Jul 9, 2026
641f3c0
fix: adjust button styling and clear selection behavior in ResourceDe…
navaspavil Jul 9, 2026
628a6a8
feat: add accessibility label for product details link in InventoryList
navaspavil Jul 9, 2026
5d4b65d
fix: add button type attribute to clear selection button in ResourceD…
navaspavil Jul 9, 2026
826b694
fix: reset selected product knowledge when closing deliveries drawer
navaspavil Jul 9, 2026
1cbc144
fix: update button styling and link behavior in InventoryList for bet…
navaspavil Jul 9, 2026
913e41e
fix: add hover effect to product knowledge selection button in Invent…
navaspavil Jul 9, 2026
6af981a
feat: add tests for All Deliveries drawer in Inventory Summary
navaspavil Jul 9, 2026
8214517
feat: add pagination to deliveries table in ProductDeliveriesDrawerCo…
navaspavil Jul 10, 2026
b6fbcfa
fix: reset page number when selecting a new product knowledge in deli…
navaspavil Jul 13, 2026
7220cb9
fix: correct class name for alignment in SupplyDeliveryTable component
navaspavil Jul 13, 2026
39b6bbd
fix: update button styling for inventory item selection in InventoryList
navaspavil Jul 13, 2026
610fe17
fix: rename Pagination component to PaginationComponent
navaspavil Jul 13, 2026
369d56f
feat: add pagination test for deliveries in All Deliveries drawer
navaspavil Jul 13, 2026
1d836a2
Merge branch 'develop' of github.com:ohcnetwork/care_fe into ENG-111-…
navaspavil Jul 13, 2026
43f696c
Update ProductDeliveriesDrawerContent to reset page on product select…
navaspavil Jul 13, 2026
30c7b6b
fix: remove initialSerialNumber prop from SupplyDeliveryTable and adj…
navaspavil Jul 13, 2026
41c7aec
Merge branch 'develop' of github.com:ohcnetwork/care_fe into ENG-111-…
navaspavil Jul 13, 2026
4e7cb3c
Merge branch 'develop' of github.com:ohcnetwork/care_fe into ENG-111-…
navaspavil Jul 14, 2026
d65681b
feat: add showLocations prop to SupplyDeliveryTable and update relate…
navaspavil Jul 14, 2026
f161038
Merge branch 'develop' of github.com:ohcnetwork/care_fe into ENG-111-…
navaspavil Jul 14, 2026
f762adc
fix: add button type to ResourceDefinitionCategoryPicker for accessib…
navaspavil Jul 14, 2026
5af00b3
feat: update delivery filtering and add serial number offset to Suppl…
navaspavil Jul 17, 2026
079cc54
Merge branch 'develop' of github.com:ohcnetwork/care_fe into ENG-111-…
navaspavil Jul 17, 2026
f3c02d0
Merge branch 'develop' of github.com:ohcnetwork/care_fe into ENG-111-…
navaspavil Jul 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions public/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -6583,6 +6583,7 @@
"view_patients": "View Patients",
"view_payments": "View Payments",
"view_prescriptions": "View Prescriptions",
"view_product_details": "View product details",
"view_profile": "View Profile",
"view_real_time_bed_status": "View real-time bed status across all wards",
"view_report": "View Report",
Expand Down
9 changes: 7 additions & 2 deletions src/components/Common/ResourceDefinitionCategoryPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -808,9 +808,11 @@ export function ResourceDefinitionCategoryPicker<T>({
variant="outline"
role="combobox"
aria-expanded={open}
type="button"
className={cn(
"justify-between px-3 py-2 w-full shadow-xs border border-gray-300 font-medium h-auto min-h-9",
disabled && "opacity-50 cursor-not-allowed",
value && !shouldHideClearButton && "rounded-r-none",
Comment thread
coderabbitai[bot] marked this conversation as resolved.
className,
)}
Comment thread
navaspavil marked this conversation as resolved.
disabled={disabled}
Expand All @@ -829,8 +831,9 @@ export function ResourceDefinitionCategoryPicker<T>({
{value && !shouldHideClearButton && (
<Button
variant="outline"
type="button"
onClick={handleClearSelection}
className="rounded-l-none -ml-2 shadow-none text-gray-400 border-gray-300"
className="rounded-l-none shadow-none text-gray-400 border-gray-300 border-l-0 h-9.5"
Comment thread
navaspavil marked this conversation as resolved.
>
Comment thread
navaspavil marked this conversation as resolved.
Comment thread
navaspavil marked this conversation as resolved.
<X />
<span className="sr-only">{t("clear_selection")}</span>
Expand Down Expand Up @@ -929,6 +932,7 @@ export function ResourceDefinitionCategoryPicker<T>({
"hover:bg-gray-50 hover:text-gray-900",
"transition-all duration-200",
disabled && "opacity-50 cursor-not-allowed",
value && !shouldHideClearButton && "rounded-r-none",
className,
)}
disabled={disabled}
Expand Down Expand Up @@ -959,8 +963,9 @@ export function ResourceDefinitionCategoryPicker<T>({
{value && !shouldHideClearButton && (
<Button
variant="outline"
type="button"
onClick={handleClearSelection}
className="rounded-l-none -ml-2 shadow-none text-gray-400 border-gray-300"
className="rounded-l-none shadow-none text-gray-400 border-gray-300 border-l-0 h-9.5"
Comment thread
navaspavil marked this conversation as resolved.
Comment thread
navaspavil marked this conversation as resolved.
>
Comment thread
navaspavil marked this conversation as resolved.
Comment thread
navaspavil marked this conversation as resolved.
Comment thread
navaspavil marked this conversation as resolved.
<X />
<span className="sr-only">{t("clear_selection")}</span>
Expand Down
129 changes: 124 additions & 5 deletions src/pages/Facility/services/inventory/InventoryList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useQuery } from "@tanstack/react-query";
import { ArrowDownUp } from "lucide-react";
import { ArrowDownUp, Truck } from "lucide-react";
import { Link } from "raviger";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
Expand All @@ -12,6 +12,7 @@ import { Badge } from "@/components/ui/badge";
import { EmptyState } from "@/components/ui/empty-state";

import Page from "@/components/Common/Page";
import PaginationComponent from "@/components/Common/Pagination";
import { TableSkeleton } from "@/components/Common/SkeletonLoading";
import {
Table,
Expand All @@ -26,14 +27,23 @@ import useFilters from "@/hooks/useFilters";

import { isLessThan, round } from "@/Utils/decimal";
import query from "@/Utils/request/query";
import {
Drawer,
DrawerContent,
DrawerHeader,
DrawerTitle,
} from "@/components/ui/drawer";
import { FilterSelect } from "@/components/ui/filter-select";
import { MonetaryDisplay } from "@/components/ui/monetary-display";
import { MonetaryComponentType } from "@/types/base/monetaryComponent/monetaryComponent";
import { ACCOUNT_STATUS_COLORS } from "@/types/billing/account/Account";
import { InventoryStatusOptions } from "@/types/inventory/product/inventory";
import inventoryApi from "@/types/inventory/product/inventoryApi";
import { ProductKnowledgeBase } from "@/types/inventory/productKnowledge/productKnowledge";
import { ACTIVE_SUPPLY_DELIVERY_STATUSES } from "@/types/inventory/supplyDelivery/supplyDelivery";
import supplyDeliveryApi from "@/types/inventory/supplyDelivery/supplyDeliveryApi";
import { ProductKnowledgeSelect } from "./ProductKnowledgeSelect";
import { SupplyDeliveryTable } from "./SupplyDeliveryTable";

const SORT_OPTIONS = {
low_to_high: "net_content",
Expand All @@ -42,6 +52,77 @@ const SORT_OPTIONS = {

type SortOptionKey = keyof typeof SORT_OPTIONS;

const DELIVERIES_PER_PAGE = 10;

// Only in-progress and completed deliveries are shown in the deliveries drawer.
const ACTIVE_DELIVERY_STATUS_FILTER = ACTIVE_SUPPLY_DELIVERY_STATUSES.join(",");

interface ProductDeliveriesDrawerContentProps {
facilityId: string;
locationId: string;
selectedProductKnowledge?: ProductKnowledgeBase;
}

function ProductDeliveriesDrawerContent({
facilityId,
locationId,
selectedProductKnowledge,
}: ProductDeliveriesDrawerContentProps) {
const { t } = useTranslation();
const [page, setPage] = useState(1);

Comment thread
navaspavil marked this conversation as resolved.
Comment thread
navaspavil marked this conversation as resolved.
Comment thread
navaspavil marked this conversation as resolved.
const { data: deliveries, isLoading } = useQuery({
queryKey: [
"supplyDeliveries",
facilityId,
locationId,
selectedProductKnowledge?.id,
page,
],
queryFn: query(supplyDeliveryApi.listSupplyDelivery, {
queryParams: {
facility: facilityId,
destination: locationId,
supplied_inventory_item_product_knowledge: selectedProductKnowledge?.id,
status: ACTIVE_DELIVERY_STATUS_FILTER,
limit: DELIVERIES_PER_PAGE,
offset: (page - 1) * DELIVERIES_PER_PAGE,
},
}),
enabled: !!selectedProductKnowledge?.id,
});
Comment thread
navaspavil marked this conversation as resolved.
Comment thread
navaspavil marked this conversation as resolved.

return (
<div className="flex flex-col overflow-y-auto pt-4 max-h-[68vh]">
{isLoading ? (
<TableSkeleton count={2} />
) : deliveries?.results && deliveries.results.length > 0 ? (
<>
<SupplyDeliveryTable
deliveries={deliveries.results}
facilityId={facilityId}
serialNumberOffset={DELIVERIES_PER_PAGE * (page - 1)}
linkToProduct
showLocations
/>
<PaginationComponent
data={{ totalCount: deliveries.count }}
onChange={(newPage) => setPage(newPage)}
defaultPerPage={DELIVERIES_PER_PAGE}
cPage={page}
/>
Comment thread
navaspavil marked this conversation as resolved.
</>
Comment thread
navaspavil marked this conversation as resolved.
) : (
<EmptyState
icon={<Truck className="size-5 text-primary-600" />}
title={t("no_deliveries_found")}
description={t("no_deliveries_found_description")}
/>
Comment thread
navaspavil marked this conversation as resolved.
)}
Comment thread
navaspavil marked this conversation as resolved.
</div>
);
}

interface InventoryListProps {
facilityId: string;
locationId: string;
Expand All @@ -58,6 +139,11 @@ export function InventoryList({ facilityId, locationId }: InventoryListProps) {
ProductKnowledgeBase | undefined
>(undefined);

// State for the "all deliveries" drawer
const [showAllDeliveries, setShowAllDeliveries] = useState(false);
const [selectedProductKnowledgeDrawer, setSelectedProductKnowledgeDrawer] =
useState<ProductKnowledgeBase | undefined>(undefined);

// Clear selected product knowledge when query parameter is cleared
useEffect(() => {
if (!qParams.product_knowledge_id) {
Expand Down Expand Up @@ -163,17 +249,31 @@ export function InventoryList({ facilityId, locationId }: InventoryListProps) {
<TableBody>
{data?.results?.map((inventory) => (
<TableRow key={inventory.id}>
<TableCell className="font-semibold">
<TableCell className="font-semibold space-x-2">
<button
type="button"
className="hover:text-gray-700 underline"
onClick={() => {
setSelectedProductKnowledgeDrawer(
inventory.product.product_knowledge,
);
Comment thread
navaspavil marked this conversation as resolved.
Comment thread
navaspavil marked this conversation as resolved.
Comment thread
navaspavil marked this conversation as resolved.
setShowAllDeliveries(true);
Comment thread
navaspavil marked this conversation as resolved.
}}
Comment thread
navaspavil marked this conversation as resolved.
>
Comment thread
greptile-apps[bot] marked this conversation as resolved.
{inventory.product.product_knowledge.name}
</button>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment thread
greptile-apps[bot] marked this conversation as resolved.
<Link
href={`/facility/${facilityId}/settings/product/${inventory.product.id}`}
basePath="/"
className="flex items-center gap-2"
onClick={(e) => e.stopPropagation()}
>
Comment thread
navaspavil marked this conversation as resolved.
{inventory.product.product_knowledge.name}
<CareIcon
icon="l-external-link-alt"
className="size-4 text-gray-500"
className="size-4 text-gray-500 hover:text-gray-700"
/>
<span className="sr-only">
{t("view_product_details")}
</span>
Comment thread
navaspavil marked this conversation as resolved.
</Link>
</TableCell>
<TableCell
Expand Down Expand Up @@ -226,6 +326,25 @@ export function InventoryList({ facilityId, locationId }: InventoryListProps) {
<div className="mt-8 flex justify-center">
<Pagination totalCount={data?.count || 0} />
</div>

<Drawer
open={showAllDeliveries}
Comment thread
navaspavil marked this conversation as resolved.
onOpenChange={(open) => {
setShowAllDeliveries(open);
if (!open) setSelectedProductKnowledgeDrawer(undefined);
}}
Comment thread
navaspavil marked this conversation as resolved.
Comment thread
navaspavil marked this conversation as resolved.
>
<DrawerContent className="max-w-7xl mx-auto px-4 sm:px-16 pb-10">
<DrawerHeader>
<DrawerTitle className="mb-2">{t("all_deliveries")}</DrawerTitle>
Comment thread
navaspavil marked this conversation as resolved.
</DrawerHeader>
<ProductDeliveriesDrawerContent
facilityId={facilityId}
locationId={locationId}
selectedProductKnowledge={selectedProductKnowledgeDrawer}
/>
Comment thread
navaspavil marked this conversation as resolved.
</DrawerContent>
</Drawer>
</Page>
);
}
34 changes: 30 additions & 4 deletions src/pages/Facility/services/inventory/SupplyDeliveryTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ interface SupplyDeliveryTableProps {
isRequester?: boolean;
facilityId?: string;
linkToProduct?: boolean;
showLocations?: boolean;
serialNumberOffset?: number;
}

export function SupplyDeliveryTable({
Expand All @@ -78,6 +80,8 @@ export function SupplyDeliveryTable({
isRequester = false,
facilityId,
linkToProduct = false,
showLocations = false,
serialNumberOffset = 0,
}: SupplyDeliveryTableProps) {
const { t } = useTranslation();
const queryClient = useQueryClient();
Expand Down Expand Up @@ -157,7 +161,7 @@ export function SupplyDeliveryTable({
// Build a map of delivery id -> serial number for non-cancelled deliveries
const serialNumberMap = useMemo(() => {
const map = new Map<string, number>();
let serial = 1;
let serial = serialNumberOffset + 1;
for (const delivery of deliveries) {
if (
ACTIVE_SUPPLY_DELIVERY_STATUSES.includes(
Comment thread
navaspavil marked this conversation as resolved.
Expand All @@ -168,7 +172,7 @@ export function SupplyDeliveryTable({
}
}
return map;
}, [deliveries]);
}, [deliveries, serialNumberOffset]);

return (
<Table>
Expand All @@ -190,6 +194,12 @@ export function SupplyDeliveryTable({
<TableHead rowSpan={2}>{t("#")}</TableHead>
<TableHead rowSpan={2}>{t("item")}</TableHead>
<TableHead rowSpan={2}>{t("batch")}</TableHead>
{showLocations && (
<>
<TableHead rowSpan={2}>{t("origin")}</TableHead>
<TableHead rowSpan={2}>{t("destination")}</TableHead>
</>
)}
<TableHead rowSpan={2}>{t("requested_qty")}</TableHead>
{!internal && <TableHead rowSpan={2}>{t("pack_size")}</TableHead>}
{!internal && <TableHead rowSpan={2}>{t("pack_qty")}</TableHead>}
Expand Down Expand Up @@ -255,10 +265,13 @@ export function SupplyDeliveryTable({
onClick={() => onDeliveryClick?.(delivery)}
>
{(() => {
const productId = internal
const internalDelivery =
internal || !!delivery.supplied_inventory_item?.product?.id;

const productId = internalDelivery
? delivery.supplied_inventory_item?.product?.id
: delivery.supplied_item?.id;
const productName = internal
const productName = internalDelivery
? delivery.supplied_inventory_item?.product?.product_knowledge
?.name
: delivery.supplied_item?.product_knowledge?.name;
Expand Down Expand Up @@ -286,6 +299,19 @@ export function SupplyDeliveryTable({
{delivery.supplied_inventory_item?.product?.batch?.lot_number ||
"-"}
</TableCell>
{showLocations && (
<>
<TableCell>
{delivery?.order?.origin?.name ||
delivery?.order?.supplier?.name ||
delivery?.order?.patient?.name ||
"-"}
</TableCell>
<TableCell>
{delivery?.order?.destination?.name || "-"}
</TableCell>
</>
)}
<TableCell>
{delivery.supply_request
? round(delivery.supply_request.quantity)
Expand Down
2 changes: 2 additions & 0 deletions src/types/inventory/requestOrder/requestOrder.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Badge } from "@/components/ui/badge";
import { PatientListRead } from "@/types/emr/patient/patient";
Comment thread
navaspavil marked this conversation as resolved.
import { TagConfig } from "@/types/emr/tagConfig/tagConfig";
import { LocationDetail } from "@/types/location/location";
import { Organization } from "@/types/organization/organization";
Expand Down Expand Up @@ -90,4 +91,5 @@ export interface RequestOrderRetrieve extends RequestOrder {
destination: LocationDetail;
supplier?: Organization;
tags: TagConfig[];
patient?: PatientListRead;
}
2 changes: 2 additions & 0 deletions src/types/inventory/supplyDelivery/supplyDelivery.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { InventoryRead } from "@/types/inventory/product/inventory";
import { ProductRead } from "@/types/inventory/product/product";
import { RequestOrderRetrieve } from "@/types/inventory/requestOrder/requestOrder";
Comment thread
navaspavil marked this conversation as resolved.
import { SupplyRequestRead } from "@/types/inventory/supplyRequest/supplyRequest";

export enum SupplyDeliveryStatus {
Expand Down Expand Up @@ -79,4 +80,5 @@ export interface SupplyDeliveryRead extends SupplyDeliveryBase {
modified_date?: string;
supply_request?: SupplyRequestRead;
extensions: Record<string, unknown>;
order?: RequestOrderRetrieve;
}
Loading
Loading