fix(dashboard, js-sdk): undefined RMA activity items (#9649)

**What**
- fix for showing removed items in rma flows

---

DEPENDS ON https://github.com/medusajs/medusa/pull/9646
FIXES CC-597
This commit is contained in:
Frane Polić authored and GitHub committed 2024-10-20 12:56:08 +00:00
1 parent 6fa98b6a4d
commit 24a1b81fb2
7 files changed
+159 -39

No files matched your search

@@ -56,6 +56,10 @@ export const useRequestOrderEdit = (
queryClient.invalidateQueries({ queryClient.invalidateQueries({
queryKey: ordersQueryKeys.changes(id), queryKey: ordersQueryKeys.changes(id),
}) })
queryClient.invalidateQueries({
queryKey: ordersQueryKeys.lineItems(id),
})
options?.onSuccess?.(data, variables, context) options?.onSuccess?.(data, variables, context)
}, },
...options, ...options,
@@ -85,6 +89,10 @@ export const useConfirmOrderEdit = (
queryKey: ordersQueryKeys.changes(id), queryKey: ordersQueryKeys.changes(id),
}) })
queryClient.invalidateQueries({
queryKey: ordersQueryKeys.lineItems(id),
})
queryClient.invalidateQueries({ queryClient.invalidateQueries({
queryKey: reservationItemsQueryKeys.lists(), queryKey: reservationItemsQueryKeys.lists(),
}) })
@@ -121,6 +129,10 @@ export const useCancelOrderEdit = (
queryClient.invalidateQueries({ queryClient.invalidateQueries({
queryKey: ordersQueryKeys.changes(orderId), queryKey: ordersQueryKeys.changes(orderId),
}) })
queryClient.invalidateQueries({
queryKey: ordersQueryKeys.lineItems(id),
})
options?.onSuccess?.(data, variables, context) options?.onSuccess?.(data, variables, context)
}, },
...options, ...options,
@@ -1,5 +1,5 @@
import { FetchError } from "@medusajs/js-sdk" import { FetchError } from "@medusajs/js-sdk"
import { HttpTypes } from "@medusajs/types" import { AdminOrderItemsFilters, HttpTypes } from "@medusajs/types"
import { import {
QueryKey, QueryKey,
useMutation, useMutation,
@@ -12,13 +12,10 @@ import { queryClient } from "../../lib/query-client"
import { queryKeysFactory, TQueryKey } from "../../lib/query-key-factory" import { queryKeysFactory, TQueryKey } from "../../lib/query-key-factory"
const ORDERS_QUERY_KEY = "orders" as const const ORDERS_QUERY_KEY = "orders" as const
const _orderKeys = queryKeysFactory(ORDERS_QUERY_KEY) as TQueryKey< const _orderKeys = queryKeysFactory(ORDERS_QUERY_KEY) as TQueryKey<"orders"> & {
"orders",
any,
string
> & {
preview: (orderId: string) => any preview: (orderId: string) => any
changes: (orderId: string) => any changes: (orderId: string) => any
lineItems: (orderId: string) => any
} }
_orderKeys.preview = function (id: string) { _orderKeys.preview = function (id: string) {
@@ -29,6 +26,10 @@ _orderKeys.changes = function (id: string) {
return [this.detail(id), "changes"] return [this.detail(id), "changes"]
} }
_orderKeys.lineItems = function (id: string) {
return [this.detail(id), "lineItems"]
}
export const ordersQueryKeys = _orderKeys export const ordersQueryKeys = _orderKeys
export const useOrder = ( export const useOrder = (
@@ -97,7 +98,7 @@ export const useOrderChanges = (
options?: Omit< options?: Omit<
UseQueryOptions< UseQueryOptions<
HttpTypes.AdminOrderChangesResponse, HttpTypes.AdminOrderChangesResponse,
Error, FetchError,
HttpTypes.AdminOrderChangesResponse, HttpTypes.AdminOrderChangesResponse,
QueryKey QueryKey
>, >,
@@ -113,6 +114,28 @@ export const useOrderChanges = (
return { ...data, ...rest } return { ...data, ...rest }
} }
export const useOrderLineItems = (
id: string,
query?: HttpTypes.AdminOrderItemsFilters,
options?: Omit<
UseQueryOptions<
HttpTypes.AdminOrderLineItemsListResponse,
FetchError,
HttpTypes.AdminOrderLineItemsListResponse,
QueryKey
>,
"queryFn" | "queryKey"
>
) => {
const { data, ...rest } = useQuery({
queryFn: async () => sdk.admin.order.listLineItems(id, query),
queryKey: ordersQueryKeys.lineItems(id),
...options,
})
return { ...data, ...rest }
}
export const useCreateOrderFulfillment = ( export const useCreateOrderFulfillment = (
orderId: string, orderId: string,
options?: UseMutationOptions< options?: UseMutationOptions<
@@ -54,7 +54,7 @@ function ActivityItems(props: ActivityItemsProps) {
<Popover.Content <Popover.Content
align="center" align="center"
side="top" side="top"
className="bg-ui-bg-component p-0 max-w-[200px] focus-visible:outline-none" className="bg-ui-bg-component max-w-[200px] p-0 focus-visible:outline-none"
> >
<div className="flex flex-col"> <div className="flex flex-col">
{!!itemsToSend?.length && ( {!!itemsToSend?.length && (
@@ -73,12 +73,10 @@ function ActivityItems(props: ActivityItemsProps) {
{item.quantity}x {item.quantity}x
</Text> </Text>
<Thumbnail <Thumbnail src={originalItem?.thumbnail} />
src={originalItem?.variant?.product?.thumbnail}
/>
<Text className="txt-compact-small text-ui-fg-subtle truncate"> <Text className="txt-compact-small text-ui-fg-subtle truncate">
{`${originalItem?.variant?.title} · ${originalItem?.variant?.product?.title}`} {`${originalItem?.variant_title} · ${originalItem?.product_title}`}
</Text> </Text>
</div> </div>
) )
@@ -105,12 +103,10 @@ function ActivityItems(props: ActivityItemsProps) {
{item.quantity}x {item.quantity}x
</Text> </Text>
<Thumbnail <Thumbnail src={originalItem?.thumbnail} />
src={originalItem?.variant?.product?.thumbnail}
/>
<Text className="txt-compact-small text-ui-fg-subtle truncate"> <Text className="txt-compact-small text-ui-fg-subtle truncate">
{`${originalItem?.variant?.title} · ${originalItem?.variant?.product?.title}`} {`${originalItem?.variant_title} · ${originalItem?.product_title}`}
</Text> </Text>
</div> </div>
) )
@@ -16,7 +16,7 @@ import {
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { AdminOrderLineItem } from "@medusajs/types" import { AdminOrderLineItem } from "@medusajs/types"
import { useOrderChanges } from "../../../../../hooks/api" import { useOrderChanges, useOrderLineItems } from "../../../../../hooks/api"
import { useCancelClaim, useClaims } from "../../../../../hooks/api/claims" import { useCancelClaim, useClaims } from "../../../../../hooks/api/claims"
import { import {
useCancelExchange, useCancelExchange,
@@ -112,14 +112,36 @@ type Activity = {
const useActivityItems = (order: AdminOrder): Activity[] => { const useActivityItems = (order: AdminOrder): Activity[] => {
const { t } = useTranslation() const { t } = useTranslation()
const itemsMap = useMemo( const { order_changes: orderChanges = [] } = useOrderChanges(order.id, {
() => new Map(order?.items?.map((i) => [i.id, i])), change_type: ["edit", "claim", "exchange", "return"],
[order.items] })
const missingLineItemIds = getMissingLineItemIds(order, orderChanges)
const { order_items: removedLineItems = [] } = useOrderLineItems(
order.id,
{
fields: "+quantity",
item_id: missingLineItemIds,
},
{
enabled: !!orderChanges.length,
}
) )
const { order_changes: orderChanges = [] } = useOrderChanges(order.id, { const itemsMap = useMemo(() => {
change_type: "edit", const _itemsMap = new Map(order?.items?.map((i) => [i.id, i]))
})
for (const id of missingLineItemIds) {
const i = removedLineItems.find((i) => i.item.id === id)
if (i) {
_itemsMap.set(id, { ...i.item, quantity: i.quantity }) // copy quantity from OrderItem to OrderLineItem
}
}
return _itemsMap
}, [order.items, removedLineItems, missingLineItemIds])
const { returns = [] } = useReturns({ const { returns = [] } = useReturns({
order_id: order.id, order_id: order.id,
@@ -226,9 +248,7 @@ const useActivityItems = (order: AdminOrder): Activity[] => {
items.push({ items.push({
title: t("orders.activity.events.fulfillment.delivered"), title: t("orders.activity.events.fulfillment.delivered"),
timestamp: fulfillment.delivered_at, timestamp: fulfillment.delivered_at,
children: ( children: <FulfillmentCreatedBody fulfillment={fulfillment} />,
<FulfillmentCreatedBody fulfillment={fulfillment} />
),
}) })
} }
@@ -334,7 +354,7 @@ const useActivityItems = (order: AdminOrder): Activity[] => {
}) })
} }
for (const edit of orderChanges) { for (const edit of orderChanges.filter((oc) => oc.change_type === "edit")) {
const isConfirmed = edit.status === "confirmed" const isConfirmed = edit.status === "confirmed"
const isPending = edit.status === "pending" const isPending = edit.status === "pending"
@@ -350,10 +370,10 @@ const useActivityItems = (order: AdminOrder): Activity[] => {
edit.status === "requested" edit.status === "requested"
? edit.requested_at ? edit.requested_at
: edit.status === "declined" : edit.status === "declined"
? edit.declined_at ? edit.declined_at
: edit.status === "canceled" : edit.status === "canceled"
? edit.canceled_at ? edit.canceled_at
: edit.created_at, : edit.created_at,
children: isConfirmed ? ( children: isConfirmed ? (
<OrderEditBody edit={edit} itemsMap={itemsMap} /> <OrderEditBody edit={edit} itemsMap={itemsMap} />
) : null, ) : null,
@@ -390,7 +410,16 @@ const useActivityItems = (order: AdminOrder): Activity[] => {
} }
return [...sortedActivities, createdAt] return [...sortedActivities, createdAt]
}, [order, payments, returns, exchanges, orderChanges, notes, isLoading]) }, [
order,
payments,
returns,
exchanges,
orderChanges,
notes,
isLoading,
itemsMap,
])
} }
type OrderActivityItemProps = PropsWithChildren<{ type OrderActivityItemProps = PropsWithChildren<{
@@ -813,14 +842,13 @@ const OrderEditBody = ({
itemsMap, itemsMap,
}: { }: {
edit: AdminOrderChange edit: AdminOrderChange
isRequested: boolean itemsMap: Map<string, AdminOrderLineItem>
itemsMap: Record<string, AdminOrderLineItem>
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const [itemsAdded, itemsRemoved] = useMemo( const [itemsAdded, itemsRemoved] = useMemo(
() => countItemsChange(edit.actions, itemsMap), () => countItemsChange(edit.actions, itemsMap),
[edit] [edit, itemsMap]
) )
return ( return (
@@ -840,21 +868,24 @@ const OrderEditBody = ({
) )
} }
/**
* Returns count of added and removed item quantity
*/
function countItemsChange( function countItemsChange(
actions: AdminOrderChange["actions"], actions: AdminOrderChange["actions"],
itemsMap: Record<string, AdminOrderLineItem> itemsMap: Map<string, AdminOrderLineItem>
) { ) {
let added = 0 let added = 0
let removed = 0 let removed = 0
actions.forEach((action) => { actions.forEach((action) => {
if (action.action === "ITEM_ADD") { if (action.action === "ITEM_ADD") {
added += action.details.quantity added += action.details!.quantity as number
} }
if (action.action === "ITEM_UPDATE") { if (action.action === "ITEM_UPDATE") {
const newQuantity: number = action.details!.quantity const newQuantity = action.details!.quantity as number
const originalQuantity: number | undefined = itemsMap.get( const originalQuantity: number | undefined = itemsMap.get(
action.details!.reference_id action.details!.reference_id as string
)?.quantity )?.quantity
if (typeof originalQuantity === "number") { if (typeof originalQuantity === "number") {
@@ -872,3 +903,28 @@ function countItemsChange(
return [added, removed] return [added, removed]
} }
/**
* Get IDs of missing line items that were removed from the order.
*/
function getMissingLineItemIds(order: AdminOrder, changes: AdminOrderChange[]) {
if (!changes?.length) {
return []
}
const retIds = new Set<string>()
const existingItemsMap = new Map(order.items.map((item) => [item.id, true]))
changes.forEach((change) => {
change.actions.forEach((action) => {
if (
(action.details!.reference_id as string).startsWith("ordli_") &&
!existingItemsMap.has(action.details!.reference_id as string)
) {
retIds.add(action.details!.reference_id as string)
}
})
})
return Array.from(retIds)
}
+13
View File
@@ -148,4 +148,17 @@ export class Order {
headers, headers,
}) })
} }
async listLineItems(
id: string,
queryParams?: FindParams & HttpTypes.AdminOrderItemsFilters,
headers?: ClientHeaders
) {
return await this.client.fetch<
PaginatedResponse<HttpTypes.AdminOrderLineItemsListResponse>
>(`/admin/orders/${id}/line-items`, {
query: queryParams,
headers,
})
}
} }
@@ -39,6 +39,19 @@ export interface AdminOrderChange
actions: AdminOrderChangeAction[] actions: AdminOrderChangeAction[]
} }
export interface AdminOrderItem {
order_id: string
item_id: string
version: number
history: {
version: {
from: number
to: number
}
}
item: AdminOrderLineItem
}
export interface AdminOrderChangeAction export interface AdminOrderChangeAction
extends Omit<BaseOrderChangeAction, "order_change" | "order"> { extends Omit<BaseOrderChangeAction, "order_change" | "order"> {
order_change: AdminOrderChange order_change: AdminOrderChange
@@ -14,6 +14,13 @@ export interface AdminOrderFilters extends FindParams, BaseOrderFilters {
updated_at?: OperatorMap<string> updated_at?: OperatorMap<string>
} }
export interface AdminOrderItemsFilters extends FindParams {
id?: string[] | string
item_id?: string[] | string
order_id?: string[] | string
version?: number[] | number
}
export interface AdminOrderChangesFilters extends BaseOrderChangesFilters {} export interface AdminOrderChangesFilters extends BaseOrderChangesFilters {}
export interface AdminOrderItemsFilters extends FindParams { export interface AdminOrderItemsFilters extends FindParams {