-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[ENG-887] Fix internal and external delivery batch failure and refine supply delivery limit UI #16661
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
[ENG-887] Fix internal and external delivery batch failure and refine supply delivery limit UI #16661
Changes from 4 commits
8af2fcc
6b395a5
5914505
88ca1a9
79db63c
d5a0115
e0520a1
90f9e34
9432850
2692ceb
77d07d2
0ba9bea
5392e1a
a1b51bc
66c7c29
78188be
9445a5c
e09e007
dcc43a2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| import { zodResolver } from "@hookform/resolvers/zod"; | ||
| import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; | ||
| import { PlusCircle, Trash2 } from "lucide-react"; | ||
| import { PlusCircle, Trash2, TriangleAlert } from "lucide-react"; | ||
| import { useQueryParams } from "raviger"; | ||
| import { useCallback, useMemo, useState } from "react"; | ||
| import { useFieldArray, useForm } from "react-hook-form"; | ||
|
|
@@ -12,6 +12,7 @@ import careConfig from "@/../care.config"; | |
| import { cn } from "@/lib/utils"; | ||
|
|
||
| import { DisablingCover } from "@/components/Common/DisablingCover"; | ||
| import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; | ||
| import Autocomplete from "@/components/ui/autocomplete"; | ||
| import { Button } from "@/components/ui/button"; | ||
| import { Card, CardContent } from "@/components/ui/card"; | ||
|
|
@@ -129,6 +130,9 @@ interface Props { | |
| origin?: string; | ||
| destination: string; | ||
| onSuccess: () => void; | ||
|
|
||
|
NikhilA8606 marked this conversation as resolved.
Outdated
|
||
| supplyDeliveriesCount: number; | ||
| isFetchingSupplyDeliveries: boolean; | ||
| } | ||
|
|
||
| export function AddSupplyDeliveryForm({ | ||
|
|
@@ -137,6 +141,8 @@ export function AddSupplyDeliveryForm({ | |
| origin, | ||
| destination, | ||
| onSuccess, | ||
| supplyDeliveriesCount, | ||
| isFetchingSupplyDeliveries, | ||
| }: Props) { | ||
| const { t } = useTranslation(); | ||
| const queryClient = useQueryClient(); | ||
|
|
@@ -237,6 +243,9 @@ export function AddSupplyDeliveryForm({ | |
| name: "items", | ||
| }); | ||
|
|
||
| const hasReachedUpsertLimit = | ||
|
NikhilA8606 marked this conversation as resolved.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two different formulas for "hit the limit" in the same component: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two formulas for the same limit in one component: |
||
| supplyDeliveriesCount >= careConfig.maxDatapointsPerUpsert; | ||
|
|
||
| const loadFromSupplyRequests = () => { | ||
| setIsSelectDialogOpen(true); | ||
| handleSelectAll(true); | ||
|
|
@@ -897,29 +906,42 @@ export function AddSupplyDeliveryForm({ | |
| </div> | ||
| </div> | ||
|
|
||
| <div className="flex flex-row gap-2 mt-4 items-end"> | ||
| <Button | ||
| type="button" | ||
| variant="outline" | ||
| onClick={handleAddAnotherItem} | ||
| > | ||
| <PlusCircle className="mr-2 size-4" /> | ||
| {t("add_another")} | ||
| </Button> | ||
| {supplyRequests?.results?.length && | ||
| supplyRequests?.results?.length > 0 && ( | ||
| <Button | ||
| type="button" | ||
| variant="secondary" | ||
| onClick={loadFromSupplyRequests} | ||
| > | ||
| {t("load_from_order")} ({supplyRequests?.count}{" "} | ||
| {t("items")} | ||
| ) | ||
| <ShortcutBadge actionId="load-from-order" /> | ||
| </Button> | ||
| )} | ||
| </div> | ||
| {supplyDeliveriesCount + fields.length >= | ||
|
NikhilA8606 marked this conversation as resolved.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This whole limit thing is enforced purely client-side. Nothing stops someone from hammering the API directly past There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hiding the whole button row behind the limit means when the cap is hit the user also loses "Load from order" and any way to interact — and the identical
NikhilA8606 marked this conversation as resolved.
|
||
| careConfig.maxDatapointsPerUpsert ? ( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When the limit is hit you replace the entire button row with a warning — including the "Load from order" button and, in the block below, nothing stops the already-added
NikhilA8606 marked this conversation as resolved.
|
||
| <Alert className="border-amber-300 bg-amber-50 text-amber-800 [&>svg]:text-amber-600 *:data-[slot=alert-description]:text-amber-700"> | ||
| <TriangleAlert /> | ||
| <AlertTitle>{t("item_limit_reached")}</AlertTitle> | ||
| <AlertDescription> | ||
| {t("max_datapoints_per_upsert_limit", { | ||
| count: careConfig.maxDatapointsPerUpsert, | ||
| })} | ||
| </AlertDescription> | ||
| </Alert> | ||
|
NikhilA8606 marked this conversation as resolved.
Outdated
NikhilA8606 marked this conversation as resolved.
Outdated
|
||
| ) : ( | ||
| <div className="flex flex-row gap-2 mt-4 items-end"> | ||
| <Button | ||
| type="button" | ||
| variant="outline" | ||
| onClick={handleAddAnotherItem} | ||
|
NikhilA8606 marked this conversation as resolved.
|
||
| > | ||
| <PlusCircle className="mr-2 size-4" /> | ||
| {t("add_another")} | ||
| </Button> | ||
| {supplyRequests?.results?.length && | ||
|
NikhilA8606 marked this conversation as resolved.
Outdated
|
||
| supplyRequests?.results?.length > 0 && ( | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
NikhilA8606 marked this conversation as resolved.
Outdated
|
||
| <Button | ||
| type="button" | ||
| variant="secondary" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| onClick={loadFromSupplyRequests} | ||
|
NikhilA8606 marked this conversation as resolved.
Outdated
|
||
| > | ||
| {t("load_from_order_with_items", { | ||
| count: supplyRequests?.count, | ||
| })} | ||
|
NikhilA8606 marked this conversation as resolved.
Outdated
|
||
| <ShortcutBadge actionId="load-from-order" /> | ||
| </Button> | ||
| )} | ||
| </div> | ||
| )} | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| <div className="flex justify-between"> | ||
| <Button | ||
|
|
@@ -952,10 +974,15 @@ export function AddSupplyDeliveryForm({ | |
| type="button" | ||
| variant="outline_primary" | ||
| onClick={loadFromSupplyRequests} | ||
| disabled={ | ||
| isProcessing || | ||
| hasReachedUpsertLimit || | ||
| isFetchingSupplyDeliveries | ||
| } | ||
| > | ||
| {t("load_from_order")} ({supplyRequests?.count}{" "} | ||
| {t("items")} | ||
| ) | ||
| {t("load_from_order_with_items", { | ||
| count: supplyRequests?.count, | ||
| })} | ||
| <ShortcutBadge actionId="load-from-order" /> | ||
| </Button> | ||
| <p>- {t("or")} -</p> | ||
|
|
@@ -971,6 +998,11 @@ export function AddSupplyDeliveryForm({ | |
| type="button" | ||
| variant="outline_primary" | ||
| onClick={() => handleAddAnotherItem()} | ||
| disabled={ | ||
| isProcessing || | ||
| hasReachedUpsertLimit || | ||
| isFetchingSupplyDeliveries | ||
| } | ||
|
NikhilA8606 marked this conversation as resolved.
Outdated
|
||
| > | ||
| <PlusCircle className="mr-2 size-4" /> | ||
| {t("add_item")} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,13 +7,15 @@ import { | |
| Hash, | ||
| MoreVertical, | ||
| Printer, | ||
| TriangleAlert, | ||
| Truck, | ||
| } from "lucide-react"; | ||
| import { Link, navigate } from "raviger"; | ||
| import { useMemo, useState } from "react"; | ||
| import { Trans, useTranslation } from "react-i18next"; | ||
| import { toast } from "sonner"; | ||
|
|
||
| import Callout from "@/CAREUI/display/Callout"; | ||
| import CareIcon from "@/CAREUI/icons/CareIcon"; | ||
| import ConfirmActionDialog from "@/components/Common/ConfirmActionDialog"; | ||
| import Page from "@/components/Common/Page"; | ||
|
|
@@ -76,6 +78,7 @@ import mutate from "@/Utils/request/mutate"; | |
| import query from "@/Utils/request/query"; | ||
| import { ExtensionContexts } from "@/Utils/schema/types"; | ||
| import { formatDateTime, formatName } from "@/Utils/utils"; | ||
| import careConfig from "@careConfig"; | ||
|
|
||
| interface Props { | ||
| facilityId: string; | ||
|
|
@@ -264,18 +267,22 @@ export function DeliveryOrderShow({ | |
|
|
||
| const isRequester = locationId === deliveryOrder?.destination.id; | ||
|
|
||
| const { data: supplyDeliveries, isLoading: isLoadingSupplyDeliveries } = | ||
| useQuery({ | ||
| queryKey: ["supplyDeliveries", deliveryOrderId], | ||
| queryFn: query.paginated(supplyDeliveryApi.listSupplyDelivery, { | ||
| queryParams: { | ||
| order: deliveryOrderId, | ||
| facility: facilityId, | ||
| ordering: "created_date", | ||
| }, | ||
| }), | ||
| enabled: !!deliveryOrderId, | ||
| }); | ||
| const { | ||
| data: supplyDeliveries, | ||
| isLoading: isLoadingSupplyDeliveries, | ||
| isFetching: isFetchingSupplyDeliveries, | ||
| } = useQuery({ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You deleted |
||
| queryKey: ["supplyDeliveries", deliveryOrderId], | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| queryFn: query.paginated(supplyDeliveryApi.listSupplyDelivery, { | ||
| queryParams: { | ||
| order: deliveryOrderId, | ||
| facility: facilityId, | ||
| ordering: "created_date", | ||
| }, | ||
|
NikhilA8606 marked this conversation as resolved.
rithviknishad marked this conversation as resolved.
|
||
| pageSize: careConfig.maxDatapointsPerUpsert, | ||
|
NikhilA8606 marked this conversation as resolved.
|
||
| }), | ||
|
NikhilA8606 marked this conversation as resolved.
|
||
| enabled: !!deliveryOrderId, | ||
| }); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You deleted
NikhilA8606 marked this conversation as resolved.
NikhilA8606 marked this conversation as resolved.
|
||
|
|
||
| const supplyOrderId = supplyDeliveries?.results?.find( | ||
| (delivery) => delivery.supply_request && delivery.supply_request.id, | ||
|
|
@@ -471,6 +478,10 @@ export function DeliveryOrderShow({ | |
| anyCompletedSupplyDeliveries, | ||
| ); | ||
|
|
||
| const hasReachedUpsertLimit = | ||
| supplyDeliveries && | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comparing
NikhilA8606 marked this conversation as resolved.
|
||
| supplyDeliveries.results.length >= careConfig.maxDatapointsPerUpsert; | ||
|
rithviknishad marked this conversation as resolved.
NikhilA8606 marked this conversation as resolved.
|
||
|
|
||
|
NikhilA8606 marked this conversation as resolved.
|
||
| return ( | ||
| <Page | ||
| title={t("delivery_order_details")} | ||
|
|
@@ -841,7 +852,7 @@ export function DeliveryOrderShow({ | |
| </div> | ||
| </CardHeader> | ||
| <CardContent className="p-2"> | ||
| {isLoadingSupplyDeliveries ? ( | ||
| {isLoadingSupplyDeliveries || isFetchingSupplyDeliveries ? ( | ||
|
NikhilA8606 marked this conversation as resolved.
Outdated
|
||
| <div className="space-y-2"> | ||
| {Array.from({ length: 3 }).map((_, i) => ( | ||
| <div key={i} className="animate-pulse"> | ||
|
|
@@ -911,14 +922,33 @@ export function DeliveryOrderShow({ | |
| <></> | ||
| )} | ||
|
|
||
| {hasReachedUpsertLimit && ( | ||
|
NikhilA8606 marked this conversation as resolved.
Outdated
|
||
| <Callout | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You switched to Also: the inner |
||
| variant="warning" | ||
| className="border border-amber-300 bg-amber-50 text-amber-800" | ||
|
NikhilA8606 marked this conversation as resolved.
|
||
| badge={ | ||
| <TriangleAlert className="size-4 shrink-0 text-amber-600" /> | ||
| } | ||
| > | ||
| <span className="flex items-center gap-2"> | ||
| {t("max_datapoints_per_upsert_limit", { | ||
| count: careConfig.maxDatapointsPerUpsert, | ||
| })} | ||
| </span> | ||
| </Callout> | ||
|
NikhilA8606 marked this conversation as resolved.
|
||
| )} | ||
|
|
||
| {/* Add New Supply Delivery Form - Always show when in draft mode */} | ||
| {canAddSupplyDeliveries && ( | ||
| {canAddSupplyDeliveries && !hasReachedUpsertLimit && ( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the parent unmounts the form entirely once the limit is hit... which means that shiny new There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When Simpler: keep the form mounted and let it own the limit UI (it already has
NikhilA8606 marked this conversation as resolved.
NikhilA8606 marked this conversation as resolved.
|
||
| <AddSupplyDeliveryForm | ||
| deliveryOrderId={deliveryOrderId} | ||
| facilityId={facilityId} | ||
| origin={deliveryOrder.origin?.id} | ||
| destination={deliveryOrder.destination.id} | ||
| onSuccess={handleSupplyDeliverySuccess} | ||
| supplyDeliveriesCount={ | ||
|
NikhilA8606 marked this conversation as resolved.
|
||
| supplyDeliveries?.results.length || 0 | ||
|
NikhilA8606 marked this conversation as resolved.
|
||
| } | ||
| /> | ||
| )} | ||
| </div> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.