fix(dashboard): Cleanup unsafe accesses to possibly undefined values in order timeline (#10454)
**What** - Fixes an unsafe access to a field that may be undefined if an order was created through a custom workflow.
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/dashboard": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(dashboard): Cleanup unsafe accesses to possibly undefined values in order timeline
|
||||||
+67
-62
@@ -1,10 +1,8 @@
|
|||||||
import { Button, IconButton, Text, Tooltip, clx, usePrompt } from "@medusajs/ui"
|
import { Button, Text, Tooltip, clx, usePrompt } from "@medusajs/ui"
|
||||||
import * as Collapsible from "@radix-ui/react-collapsible"
|
import * as Collapsible from "@radix-ui/react-collapsible"
|
||||||
|
|
||||||
import { PropsWithChildren, ReactNode, useMemo, useState } from "react"
|
import { PropsWithChildren, ReactNode, useMemo, useState } from "react"
|
||||||
import { Link } from "react-router-dom"
|
|
||||||
|
|
||||||
import { XMarkMini } from "@medusajs/icons"
|
|
||||||
import {
|
import {
|
||||||
AdminClaim,
|
AdminClaim,
|
||||||
AdminExchange,
|
AdminExchange,
|
||||||
@@ -16,6 +14,7 @@ import {
|
|||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
|
|
||||||
import { AdminOrderLineItem } from "@medusajs/types"
|
import { AdminOrderLineItem } from "@medusajs/types"
|
||||||
|
import { By } from "../../../../../components/common/user-link"
|
||||||
import {
|
import {
|
||||||
useCancelOrderTransfer,
|
useCancelOrderTransfer,
|
||||||
useCustomer,
|
useCustomer,
|
||||||
@@ -29,12 +28,11 @@ import {
|
|||||||
} from "../../../../../hooks/api/exchanges"
|
} from "../../../../../hooks/api/exchanges"
|
||||||
import { useCancelReturn, useReturns } from "../../../../../hooks/api/returns"
|
import { useCancelReturn, useReturns } from "../../../../../hooks/api/returns"
|
||||||
import { useDate } from "../../../../../hooks/use-date"
|
import { useDate } from "../../../../../hooks/use-date"
|
||||||
|
import { getFormattedAddress } from "../../../../../lib/addresses"
|
||||||
import { getStylizedAmount } from "../../../../../lib/money-amount-helpers"
|
import { getStylizedAmount } from "../../../../../lib/money-amount-helpers"
|
||||||
import { getPaymentsFromOrder } from "../order-payment-section"
|
import { getPaymentsFromOrder } from "../order-payment-section"
|
||||||
import ActivityItems from "./activity-items"
|
import ActivityItems from "./activity-items"
|
||||||
import { By, UserLink } from "../../../../../components/common/user-link"
|
|
||||||
import ChangeDetailsTooltip from "./change-details-tooltip"
|
import ChangeDetailsTooltip from "./change-details-tooltip"
|
||||||
import { getFormattedAddress } from "../../../../../lib/addresses"
|
|
||||||
|
|
||||||
type OrderTimelineProps = {
|
type OrderTimelineProps = {
|
||||||
order: AdminOrder
|
order: AdminOrder
|
||||||
@@ -455,7 +453,7 @@ const useActivityItems = (order: AdminOrder): Activity[] => {
|
|||||||
),
|
),
|
||||||
timestamp: update.created_at,
|
timestamp: update.created_at,
|
||||||
children: (
|
children: (
|
||||||
<div className="mt-2 flex text-sm gap-x-2 text-ui-fg-subtle">
|
<div className="text-ui-fg-subtle mt-2 flex gap-x-2 text-sm">
|
||||||
{t("fields.by")} <By id={update.created_by} />
|
{t("fields.by")} <By id={update.created_by} />
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
@@ -477,7 +475,7 @@ const useActivityItems = (order: AdminOrder): Activity[] => {
|
|||||||
),
|
),
|
||||||
timestamp: update.created_at,
|
timestamp: update.created_at,
|
||||||
children: (
|
children: (
|
||||||
<div className="mt-2 flex text-sm gap-x-2 text-ui-fg-subtle">
|
<div className="text-ui-fg-subtle mt-2 flex gap-x-2 text-sm">
|
||||||
{t("fields.by")} <By id={update.created_by} />
|
{t("fields.by")} <By id={update.created_by} />
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
@@ -495,7 +493,7 @@ const useActivityItems = (order: AdminOrder): Activity[] => {
|
|||||||
),
|
),
|
||||||
timestamp: update.created_at,
|
timestamp: update.created_at,
|
||||||
children: (
|
children: (
|
||||||
<div className="mt-2 flex text-sm gap-x-2 text-ui-fg-subtle">
|
<div className="text-ui-fg-subtle mt-2 flex gap-x-2 text-sm">
|
||||||
{t("fields.by")} <By id={update.created_by} />
|
{t("fields.by")} <By id={update.created_by} />
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
@@ -674,64 +672,67 @@ const OrderActivityCollapsible = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const NoteBody = ({ note }: { note: Note }) => {
|
/**
|
||||||
const { t } = useTranslation()
|
* TODO: Add once notes are supported.
|
||||||
const prompt = usePrompt()
|
*/
|
||||||
|
// const NoteBody = ({ note }: { note: Note }) => {
|
||||||
|
// const { t } = useTranslation()
|
||||||
|
// const prompt = usePrompt()
|
||||||
|
|
||||||
const { first_name, last_name, email } = note.author || {}
|
// const { first_name, last_name, email } = note.author || {}
|
||||||
const name = [first_name, last_name].filter(Boolean).join(" ")
|
// const name = [first_name, last_name].filter(Boolean).join(" ")
|
||||||
|
|
||||||
const byLine = t("orders.activity.events.note.byLine", {
|
// const byLine = t("orders.activity.events.note.byLine", {
|
||||||
author: name || email,
|
// author: name || email,
|
||||||
})
|
// })
|
||||||
|
|
||||||
const { mutateAsync } = {} // useAdminDeleteNote(note.id)
|
// const { mutateAsync } = {} // useAdminDeleteNote(note.id)
|
||||||
|
|
||||||
const handleDelete = async () => {
|
// const handleDelete = async () => {
|
||||||
const res = await prompt({
|
// const res = await prompt({
|
||||||
title: t("general.areYouSure"),
|
// title: t("general.areYouSure"),
|
||||||
description: "This action cannot be undone",
|
// description: "This action cannot be undone",
|
||||||
confirmText: t("actions.delete"),
|
// confirmText: t("actions.delete"),
|
||||||
cancelText: t("actions.cancel"),
|
// cancelText: t("actions.cancel"),
|
||||||
})
|
// })
|
||||||
|
|
||||||
if (!res) {
|
// if (!res) {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
await mutateAsync()
|
// await mutateAsync()
|
||||||
}
|
// }
|
||||||
|
|
||||||
return (
|
// return (
|
||||||
<div className="flex flex-col gap-y-2 pt-2">
|
// <div className="flex flex-col gap-y-2 pt-2">
|
||||||
<div className="bg-ui-bg-component shadow-borders-base group grid grid-cols-[1fr_20px] items-start gap-x-2 text-pretty rounded-r-2xl rounded-bl-md rounded-tl-xl px-3 py-1.5">
|
// <div className="bg-ui-bg-component shadow-borders-base group grid grid-cols-[1fr_20px] items-start gap-x-2 text-pretty rounded-r-2xl rounded-bl-md rounded-tl-xl px-3 py-1.5">
|
||||||
<div className="flex h-full min-h-7 items-center">
|
// <div className="flex h-full min-h-7 items-center">
|
||||||
<Text size="xsmall" className="text-ui-fg-subtle">
|
// <Text size="xsmall" className="text-ui-fg-subtle">
|
||||||
{note.value}
|
// {note.value}
|
||||||
</Text>
|
// </Text>
|
||||||
</div>
|
// </div>
|
||||||
<IconButton
|
// <IconButton
|
||||||
size="small"
|
// size="small"
|
||||||
variant="transparent"
|
// variant="transparent"
|
||||||
className="transition-fg invisible opacity-0 group-hover:visible group-hover:opacity-100"
|
// className="transition-fg invisible opacity-0 group-hover:visible group-hover:opacity-100"
|
||||||
type="button"
|
// type="button"
|
||||||
onClick={handleDelete}
|
// onClick={handleDelete}
|
||||||
>
|
// >
|
||||||
<span className="sr-only">
|
// <span className="sr-only">
|
||||||
{t("orders.activity.comment.deleteButtonText")}
|
// {t("orders.activity.comment.deleteButtonText")}
|
||||||
</span>
|
// </span>
|
||||||
<XMarkMini className="text-ui-fg-muted" />
|
// <XMarkMini className="text-ui-fg-muted" />
|
||||||
</IconButton>
|
// </IconButton>
|
||||||
</div>
|
// </div>
|
||||||
<Link
|
// <Link
|
||||||
to={`/settings/users/${note.author_id}`}
|
// to={`/settings/users/${note.author_id}`}
|
||||||
className="text-ui-fg-subtle hover:text-ui-fg-base transition-fg w-fit"
|
// className="text-ui-fg-subtle hover:text-ui-fg-base transition-fg w-fit"
|
||||||
>
|
// >
|
||||||
<Text size="small">{byLine}</Text>
|
// <Text size="small">{byLine}</Text>
|
||||||
</Link>
|
// </Link>
|
||||||
</div>
|
// </div>
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
const FulfillmentCreatedBody = ({
|
const FulfillmentCreatedBody = ({
|
||||||
fulfillment,
|
fulfillment,
|
||||||
@@ -1085,11 +1086,15 @@ function getMissingLineItemIds(order: AdminOrder, changes: AdminOrderChange[]) {
|
|||||||
|
|
||||||
changes.forEach((change) => {
|
changes.forEach((change) => {
|
||||||
change.actions.forEach((action) => {
|
change.actions.forEach((action) => {
|
||||||
|
if (!action.details?.reference_id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(action.details!.reference_id as string).startsWith("ordli_") &&
|
(action.details.reference_id as string).startsWith("ordli_") &&
|
||||||
!existingItemsMap.has(action.details!.reference_id as string)
|
!existingItemsMap.has(action.details.reference_id as string)
|
||||||
) {
|
) {
|
||||||
retIds.add(action.details!.reference_id as string)
|
retIds.add(action.details.reference_id as string)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { RouteFocusModal } from "../../../components/modals"
|
import { RouteFocusModal } from "../../../components/modals"
|
||||||
import { CreateShippingProfileForm } from "./components/create-shipping-profile-form"
|
import { CreateShippingProfileForm } from "./components/create-shipping-profile-form"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user