feat(dashboard): activity section events (#7929)

* feat: activity section events

* fix: hide tax section

* fix: display shipping methods

* fix: reorg summary totals according to design
This commit is contained in:
Frane Polić
2024-07-03 20:48:53 +02:00
committed by GitHub
parent 6713d76db3
commit b3e55bfa48
4 changed files with 66 additions and 85 deletions

View File

@@ -767,13 +767,11 @@
"canceled": "Payment canceled"
},
"fulfillment": {
"created": "Fulfillment created",
"created": "Items fulfilled",
"canceled": "Fulfillment canceled",
"shipped": "Fulfillment shipped",
"itemsFulfilledFrom_one": "{{count}} item fulfilled from {{location}}",
"itemsFulfilledFrom_other": "{{count}} items fulfilled from {{location}}",
"itemsFulfilled_one": "{{count}} item fulfilled",
"itemsFulfilled_other": "{{count}} items fulfilled"
"shipped": "Items shipped",
"items_one": "{{count}} item",
"items_other": "{{count}} items"
},
"return": {
"created": "Return created"
@@ -1881,6 +1879,7 @@
"orders": "Orders",
"account": "Account",
"total": "Total",
"paidTotal": "Paid total",
"totalExclTax": "Total excl. tax",
"subtotal": "Subtotal",
"shipping": "Shipping",

View File

@@ -1,4 +1,3 @@
import { Fulfillment, Note, Order } from "@medusajs/medusa"
import { IconButton, Text, Tooltip, clx, usePrompt } from "@medusajs/ui"
import * as Collapsible from "@radix-ui/react-collapsible"
@@ -6,11 +5,11 @@ import { PropsWithChildren, ReactNode, useMemo, useState } from "react"
import { Link } from "react-router-dom"
import { XMarkMini } from "@medusajs/icons"
import { AdminOrder } from "@medusajs/types"
import { AdminFulfillment, AdminOrder } from "@medusajs/types"
import { useTranslation } from "react-i18next"
import { Skeleton } from "../../../../../components/common/skeleton"
import { useDate } from "../../../../../hooks/use-date"
import { useStockLocation } from "../../../../../hooks/api/stock-locations"
import { getStylizedAmount } from "../../../../../lib/money-amount-helpers"
type OrderTimelineProps = {
order: AdminOrder
@@ -78,7 +77,7 @@ type Activity = {
children?: ReactNode
}
const useActivityItems = (order: Order) => {
const useActivityItems = (order: AdminOrder) => {
const { t } = useTranslation()
const notes = []
@@ -141,20 +140,34 @@ const useActivityItems = (order: Order) => {
// }
// }
// for (const fulfillment of order.fulfillments) {
// items.push({
// title: t("orders.activity.events.fulfillment.created"),
// timestamp: fulfillment.created_at,
// children: <FulfillmentCreatedBody fulfillment={fulfillment} />,
// })
//
// if (fulfillment.shipped_at) {
// items.push({
// title: t("orders.activity.events.fulfillment.shipped"),
// timestamp: fulfillment.shipped_at,
// })
// }
// }
for (const fulfillment of order.fulfillments) {
items.push({
title: t("orders.activity.events.fulfillment.created"),
timestamp: fulfillment.created_at,
children: <FulfillmentCreatedBody fulfillment={fulfillment} />,
})
if (fulfillment.shipped_at) {
items.push({
title: t("orders.activity.events.fulfillment.shipped"),
timestamp: fulfillment.shipped_at,
children: (
<FulfillmentCreatedBody fulfillment={fulfillment} isShipment />
),
})
}
if (fulfillment.canceled_at) {
items.push({
title: t("orders.activity.events.fulfillment.canceled"),
timestamp: fulfillment.canceled_at,
})
}
}
/**
* TODO: revisit when API is fixed to fetch returns of an order
*/
// for (const ret of order.returns) {
// items.push({
@@ -187,9 +200,7 @@ const useActivityItems = (order: Order) => {
timestamp: order.created_at,
children: (
<Text size="small" className="text-ui-fg-subtle">
{t("orders.activity.events.placed.fromSalesChannel", {
salesChannel: order.sales_channel.name,
})}
{getStylizedAmount(order.total, order.currency_code)}
</Text>
),
}
@@ -311,7 +322,7 @@ const NoteBody = ({ note }: { note: Note }) => {
author: name || email,
})
const { mutateAsync } = useAdminDeleteNote(note.id)
const { mutateAsync } = {} // useAdminDeleteNote(note.id)
const handleDelete = async () => {
const res = await prompt({
@@ -362,44 +373,21 @@ const NoteBody = ({ note }: { note: Note }) => {
const FulfillmentCreatedBody = ({
fulfillment,
}: {
fulfillment: Fulfillment
fulfillment: AdminFulfillment
}) => {
const { t } = useTranslation()
const { stock_location, isLoading, isError, error } = useStockLocation(
fulfillment.location_id!,
undefined,
{
enabled: !!fulfillment.location_id,
}
)
const numberOfItems = fulfillment.items.reduce((acc, item) => {
return acc + item.quantity
}, 0)
const triggerText = stock_location
? t("orders.activity.events.fulfillment.itemsFulfilledFrom", {
count: numberOfItems,
location: stock_location.name,
})
: t("orders.activity.events.fulfillment.itemsFulfilled", {
count: numberOfItems,
})
if (isError) {
throw error
}
return (
<div>
{isLoading ? (
<Skeleton className="h-7 w-full" />
) : (
<Text size="small" className="text-ui-fg-subtle">
{triggerText}
</Text>
)}
<Text size="small" className="text-ui-fg-subtle">
{t("orders.activity.events.fulfillment.items", {
count: numberOfItems,
})}
</Text>
</div>
)
}

View File

@@ -192,14 +192,9 @@ const CostBreakdown = ({ order }: { order: AdminOrder }) => {
return (
<div className="text-ui-fg-subtle flex flex-col gap-y-2 px-6 py-4">
<Cost
label={t("fields.subtotal")}
secondaryValue={t("general.items", { count: order.items.length })}
value={getLocaleAmount(order.subtotal, order.currency_code)}
/>
<Cost
label={t("fields.discount")}
// TODO: ORDER<>DISCOUNTS link
// TODO: DISCOUNTS -> moved to line items now
// secondaryValue={
// order.discounts.length > 0
// ? order.discounts.map((d) => d.code).join(", ")
@@ -213,22 +208,9 @@ const CostBreakdown = ({ order }: { order: AdminOrder }) => {
/>
<Cost
label={t("fields.shipping")}
// TODO: ORDER<>SHIPPING link
// secondaryValue={order.shipping_methods
// .map((sm) => sm.shipping_option.name)
// .join(", ")}
secondaryValue={order.shipping_methods.map((sm) => sm.name).join(", ")}
value={getLocaleAmount(order.shipping_total, order.currency_code)}
/>
<Cost
label={t("fields.tax")}
// TODO: TAX_RATE is missing on order
secondaryValue={`${order.tax_rate || 0}%`}
value={
order.tax_total
? getLocaleAmount(order.tax_total, order.currency_code)
: "-"
}
/>
</div>
)
}
@@ -237,13 +219,23 @@ const Total = ({ order }: { order: AdminOrder }) => {
const { t } = useTranslation()
return (
<div className="text-ui-fg-base flex items-center justify-between px-6 py-4">
<Text size="small" leading="compact" weight="plus">
{t("fields.total")}
</Text>
<Text size="small" leading="compact" weight="plus">
{getStylizedAmount(order.total, order.currency_code)}
</Text>
<div className=" flex flex-col gap-y-2 px-6 py-4">
<div className="text-ui-fg-base flex items-center justify-between">
<Text className="text-ui-fg-subtle" size="small" leading="compact">
{t("fields.total")}
</Text>
<Text className="text-ui-fg-subtle" size="small" leading="compact">
{getStylizedAmount(order.total, order.currency_code)}
</Text>
</div>
<div className="text-ui-fg-base flex items-center justify-between">
<Text className="text-ui-fg-subtle" size="small" leading="compact">
{t("fields.paidTotal")}
</Text>
<Text className="text-ui-fg-subtle" size="small" leading="compact">
{/*TODO*/}-
</Text>
</div>
</div>
)
}

View File

@@ -2,6 +2,7 @@ const DEFAULT_PROPERTIES = [
"id",
"status",
"created_at",
"canceled_at",
"email",
// "payment_status", // -> TODO replacement for this
"display_id",
@@ -22,6 +23,7 @@ const DEFAULT_RELATIONS = [
"*billing_address",
"*sales_channel",
"*promotion",
"*shipping_methods",
"*fulfillments",
"*fulfillments.items",
"*fulfillments.labels",