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ć
2024-10-20 14:56:08 +02:00
committed by GitHub
parent 6fa98b6a4d
commit 24a1b81fb2
7 changed files with 159 additions and 39 deletions

View File

@@ -56,6 +56,10 @@ export const useRequestOrderEdit = (
queryClient.invalidateQueries({
queryKey: ordersQueryKeys.changes(id),
})
queryClient.invalidateQueries({
queryKey: ordersQueryKeys.lineItems(id),
})
options?.onSuccess?.(data, variables, context)
},
...options,
@@ -85,6 +89,10 @@ export const useConfirmOrderEdit = (
queryKey: ordersQueryKeys.changes(id),
})
queryClient.invalidateQueries({
queryKey: ordersQueryKeys.lineItems(id),
})
queryClient.invalidateQueries({
queryKey: reservationItemsQueryKeys.lists(),
})
@@ -121,6 +129,10 @@ export const useCancelOrderEdit = (
queryClient.invalidateQueries({
queryKey: ordersQueryKeys.changes(orderId),
})
queryClient.invalidateQueries({
queryKey: ordersQueryKeys.lineItems(id),
})
options?.onSuccess?.(data, variables, context)
},
...options,

View File

@@ -1,5 +1,5 @@
import { FetchError } from "@medusajs/js-sdk"
import { HttpTypes } from "@medusajs/types"
import { AdminOrderItemsFilters, HttpTypes } from "@medusajs/types"
import {
QueryKey,
useMutation,
@@ -12,13 +12,10 @@ import { queryClient } from "../../lib/query-client"
import { queryKeysFactory, TQueryKey } from "../../lib/query-key-factory"
const ORDERS_QUERY_KEY = "orders" as const
const _orderKeys = queryKeysFactory(ORDERS_QUERY_KEY) as TQueryKey<
"orders",
any,
string
> & {
const _orderKeys = queryKeysFactory(ORDERS_QUERY_KEY) as TQueryKey<"orders"> & {
preview: (orderId: string) => any
changes: (orderId: string) => any
lineItems: (orderId: string) => any
}
_orderKeys.preview = function (id: string) {
@@ -29,6 +26,10 @@ _orderKeys.changes = function (id: string) {
return [this.detail(id), "changes"]
}
_orderKeys.lineItems = function (id: string) {
return [this.detail(id), "lineItems"]
}
export const ordersQueryKeys = _orderKeys
export const useOrder = (
@@ -97,7 +98,7 @@ export const useOrderChanges = (
options?: Omit<
UseQueryOptions<
HttpTypes.AdminOrderChangesResponse,
Error,
FetchError,
HttpTypes.AdminOrderChangesResponse,
QueryKey
>,
@@ -113,6 +114,28 @@ export const useOrderChanges = (
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 = (
orderId: string,
options?: UseMutationOptions<

View File

@@ -54,7 +54,7 @@ function ActivityItems(props: ActivityItemsProps) {
<Popover.Content
align="center"
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">
{!!itemsToSend?.length && (
@@ -73,12 +73,10 @@ function ActivityItems(props: ActivityItemsProps) {
{item.quantity}x
</Text>
<Thumbnail
src={originalItem?.variant?.product?.thumbnail}
/>
<Thumbnail src={originalItem?.thumbnail} />
<Text className="txt-compact-small text-ui-fg-subtle truncate">
{`${originalItem?.variant?.title} · ${originalItem?.variant?.product?.title}`}
{`${originalItem?.variant_title} · ${originalItem?.product_title}`}
</Text>
</div>
)
@@ -105,12 +103,10 @@ function ActivityItems(props: ActivityItemsProps) {
{item.quantity}x
</Text>
<Thumbnail
src={originalItem?.variant?.product?.thumbnail}
/>
<Thumbnail src={originalItem?.thumbnail} />
<Text className="txt-compact-small text-ui-fg-subtle truncate">
{`${originalItem?.variant?.title} · ${originalItem?.variant?.product?.title}`}
{`${originalItem?.variant_title} · ${originalItem?.product_title}`}
</Text>
</div>
)

View File

@@ -16,7 +16,7 @@ import {
import { useTranslation } from "react-i18next"
import { AdminOrderLineItem } from "@medusajs/types"
import { useOrderChanges } from "../../../../../hooks/api"
import { useOrderChanges, useOrderLineItems } from "../../../../../hooks/api"
import { useCancelClaim, useClaims } from "../../../../../hooks/api/claims"
import {
useCancelExchange,
@@ -112,14 +112,36 @@ type Activity = {
const useActivityItems = (order: AdminOrder): Activity[] => {
const { t } = useTranslation()
const itemsMap = useMemo(
() => new Map(order?.items?.map((i) => [i.id, i])),
[order.items]
const { order_changes: orderChanges = [] } = useOrderChanges(order.id, {
change_type: ["edit", "claim", "exchange", "return"],
})
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, {
change_type: "edit",
})
const itemsMap = useMemo(() => {
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({
order_id: order.id,
@@ -226,9 +248,7 @@ const useActivityItems = (order: AdminOrder): Activity[] => {
items.push({
title: t("orders.activity.events.fulfillment.delivered"),
timestamp: fulfillment.delivered_at,
children: (
<FulfillmentCreatedBody fulfillment={fulfillment} />
),
children: <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 isPending = edit.status === "pending"
@@ -350,10 +370,10 @@ const useActivityItems = (order: AdminOrder): Activity[] => {
edit.status === "requested"
? edit.requested_at
: edit.status === "declined"
? edit.declined_at
: edit.status === "canceled"
? edit.canceled_at
: edit.created_at,
? edit.declined_at
: edit.status === "canceled"
? edit.canceled_at
: edit.created_at,
children: isConfirmed ? (
<OrderEditBody edit={edit} itemsMap={itemsMap} />
) : null,
@@ -390,7 +410,16 @@ const useActivityItems = (order: AdminOrder): Activity[] => {
}
return [...sortedActivities, createdAt]
}, [order, payments, returns, exchanges, orderChanges, notes, isLoading])
}, [
order,
payments,
returns,
exchanges,
orderChanges,
notes,
isLoading,
itemsMap,
])
}
type OrderActivityItemProps = PropsWithChildren<{
@@ -813,14 +842,13 @@ const OrderEditBody = ({
itemsMap,
}: {
edit: AdminOrderChange
isRequested: boolean
itemsMap: Record<string, AdminOrderLineItem>
itemsMap: Map<string, AdminOrderLineItem>
}) => {
const { t } = useTranslation()
const [itemsAdded, itemsRemoved] = useMemo(
() => countItemsChange(edit.actions, itemsMap),
[edit]
[edit, itemsMap]
)
return (
@@ -840,21 +868,24 @@ const OrderEditBody = ({
)
}
/**
* Returns count of added and removed item quantity
*/
function countItemsChange(
actions: AdminOrderChange["actions"],
itemsMap: Record<string, AdminOrderLineItem>
itemsMap: Map<string, AdminOrderLineItem>
) {
let added = 0
let removed = 0
actions.forEach((action) => {
if (action.action === "ITEM_ADD") {
added += action.details.quantity
added += action.details!.quantity as number
}
if (action.action === "ITEM_UPDATE") {
const newQuantity: number = action.details!.quantity
const newQuantity = action.details!.quantity as number
const originalQuantity: number | undefined = itemsMap.get(
action.details!.reference_id
action.details!.reference_id as string
)?.quantity
if (typeof originalQuantity === "number") {
@@ -872,3 +903,28 @@ function countItemsChange(
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)
}

View File

@@ -148,4 +148,17 @@ export class Order {
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,
})
}
}

View File

@@ -39,6 +39,19 @@ export interface AdminOrderChange
actions: AdminOrderChangeAction[]
}
export interface AdminOrderItem {
order_id: string
item_id: string
version: number
history: {
version: {
from: number
to: number
}
}
item: AdminOrderLineItem
}
export interface AdminOrderChangeAction
extends Omit<BaseOrderChangeAction, "order_change" | "order"> {
order_change: AdminOrderChange

View File

@@ -14,6 +14,13 @@ export interface AdminOrderFilters extends FindParams, BaseOrderFilters {
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 AdminOrderItemsFilters extends FindParams {