Skip to content

Commit

Permalink
feat(dashboard,medusa): Draft order list page (#6658)
Browse files Browse the repository at this point in the history
**What**
- (dashboard) Adds list page for Draft Order domain
- (medusa) Adds the ability to filter draft orders
  • Loading branch information
kasperkristensen authored Mar 11, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent c51a67a commit 78e5ec4
Showing 21 changed files with 486 additions and 55 deletions.
6 changes: 6 additions & 0 deletions .changeset/purple-sloths-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@medusajs/client-types": patch
"@medusajs/medusa": patch
---

fix(medusa): Add missing query params to draft order list endpoint
Original file line number Diff line number Diff line change
@@ -255,7 +255,12 @@
}
},
"draftOrders": {
"domain": "Draft Orders"
"domain": "Draft Orders",
"deleteWarning": "You are about to delete the draft order {{id}}. This action cannot be undone.",
"status": {
"open": "Open",
"completed": "Completed"
}
},
"discounts": {
"domain": "Discounts",
Original file line number Diff line number Diff line change
@@ -109,11 +109,13 @@ const router = createBrowserRouter([
children: [
{
index: true,
lazy: () => import("../../routes/draft-orders/list"),
lazy: () =>
import("../../routes/draft-orders/draft-order-list"),
},
{
path: ":id",
lazy: () => import("../../routes/draft-orders/details"),
lazy: () =>
import("../../routes/draft-orders/draft-order-detail"),
},
],
},

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const DraftOrderDetails = () => {
return <div>Draft Order Details</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { DraftOrderDetails as Component } from "./details"
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Button, Container, Heading } from "@medusajs/ui"
import { useAdminDraftOrders } from "medusa-react"
import { useTranslation } from "react-i18next"
import { Link } from "react-router-dom"
import { DataTable } from "../../../../../components/table/data-table"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { useDraftOrderTableColumns } from "./use-draft-order-table-columns"
import { useDraftOrderTableFilters } from "./use-draft-order-table-filters"
import { useDraftOrderTableQuery } from "./use-draft-order-table-query"

const PAGE_SIZE = 20

export const DraftOrderListTable = () => {
const { t } = useTranslation()

const { searchParams, raw } = useDraftOrderTableQuery({
pageSize: PAGE_SIZE,
})
const { draft_orders, count, isLoading, isError, error } =
useAdminDraftOrders(
{
...searchParams,
expand: "cart,cart.customer",
},
{
keepPreviousData: true,
}
)

const columns = useDraftOrderTableColumns()
const filters = useDraftOrderTableFilters()

const { table } = useDataTable({
data: draft_orders || [],
columns,
count,
enablePagination: true,
getRowId: (row) => row.id,
pageSize: PAGE_SIZE,
})

if (isError) {
throw error
}

return (
<Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4">
<Heading>{t("draftOrders.domain")}</Heading>
<Button variant="secondary" size="small" asChild>
<Link to="create">{t("actions.create")}</Link>
</Button>
</div>
<DataTable
table={table}
isLoading={isLoading}
columns={columns}
filters={filters}
pageSize={PAGE_SIZE}
count={count}
search
pagination
navigateTo={(row) => row.original.id}
orderBy={["status", "created_at", "updated_at"]}
queryObject={raw}
/>
</Container>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { PencilSquare, Trash } from "@medusajs/icons"
import { DraftOrder } from "@medusajs/medusa"
import { usePrompt } from "@medusajs/ui"
import { useAdminDeleteDraftOrder } from "medusa-react"
import { useTranslation } from "react-i18next"
import { ActionMenu } from "../../../../../components/common/action-menu"

export const DraftOrderTableActions = ({
draftOrder,
}: {
draftOrder: DraftOrder
}) => {
const { t } = useTranslation()
const prompt = usePrompt()

const { mutateAsync } = useAdminDeleteDraftOrder(draftOrder.id)

const handleDelete = async () => {
const res = await prompt({
title: t("general.areYouSure"),
description: t("draftOrders.deleteWarning", {
id: `#${draftOrder.display_id}`,
}),
confirmText: t("actions.delete"),
cancelText: t("actions.cancel"),
})

if (!res) {
return
}

await mutateAsync()
}

return (
<ActionMenu
groups={[
{
actions: [
{
label: t("actions.edit"),
to: `${draftOrder.id}/edit`,
icon: <PencilSquare />,
},
],
},
{
actions: [
{
label: t("actions.delete"),
onClick: handleDelete,
icon: <Trash />,
},
],
},
]}
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./draft-order-list-table"
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { DraftOrder } from "@medusajs/medusa"
import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react"
import { useTranslation } from "react-i18next"
import { DateCell } from "../../../../../components/table/table-cells/common/date-cell"
import { StatusCell } from "../../../../../components/table/table-cells/common/status-cell"
import {
CustomerCell,
CustomerHeader,
} from "../../../../../components/table/table-cells/order/customer-cell"
import { DraftOrderTableActions } from "./draft-order-table-actions"

const columnHelper = createColumnHelper<DraftOrder>()

export const useDraftOrderTableColumns = () => {
const { t } = useTranslation()

return useMemo(
() => [
columnHelper.accessor("display_id", {
header: t("fields.id"),
cell: ({ getValue }) => (
<div className="flex size-full items-center overflow-hidden">
<span className="truncate">#{getValue()}</span>
</div>
),
}),
columnHelper.accessor("status", {
header: t("fields.status"),
cell: ({ getValue }) => {
const status = getValue()

const { color, label } = {
open: { color: "orange", label: t("draftOrders.status.open") },
completed: {
color: "green",
label: t("draftOrders.status.completed"),
},
}[status] as { color: "green" | "orange"; label: string }

return <StatusCell color={color}>{label}</StatusCell>
},
}),
columnHelper.accessor("order", {
header: t("fields.order"),
cell: ({ getValue }) => {
const displayId = getValue()?.display_id

return (
<div className="flex size-full items-center overflow-hidden">
<span className="truncate">
{displayId ? `#${displayId}` : "-"}
</span>
</div>
)
},
}),
columnHelper.accessor("cart.customer", {
header: () => <CustomerHeader />,
cell: ({ getValue }) => {
const customer = getValue()

return <CustomerCell customer={customer} />
},
}),
columnHelper.accessor("created_at", {
header: t("fields.createdAt"),
cell: ({ getValue }) => {
const date = getValue()

return <DateCell date={date} />
},
}),
columnHelper.display({
id: "actions",
cell: ({ row }) => <DraftOrderTableActions draftOrder={row.original} />,
}),
],
[t]
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useTranslation } from "react-i18next"
import { Filter } from "../../../../../components/table/data-table"

export const useDraftOrderTableFilters = () => {
const { t } = useTranslation()

const filters: Filter[] = [
{
type: "select",
multiple: true,
key: "status",
label: t("fields.status"),
options: [
{
label: t("draftOrders.status.open"),
value: "open",
},
{
label: t("draftOrders.status.completed"),
value: "completed",
},
],
},
]

const dateFilters: Filter[] = [
{ label: t("fields.createdAt"), key: "created_at" },
{ label: t("fields.updatedAt"), key: "updated_at" },
].map((f) => ({
key: f.key,
label: f.label,
type: "date",
}))

return [...filters, ...dateFilters]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { AdminGetDraftOrdersParams } from "@medusajs/medusa"
import { useQueryParams } from "../../../../../hooks/use-query-params"

export const useDraftOrderTableQuery = ({
pageSize = 20,
prefix,
}: {
pageSize?: number
prefix?: string
}) => {
const raw = useQueryParams(
["offset", "q", "order", "status", "created_at", "updated_at"],
prefix
)

const { status, offset, created_at, updated_at, ...rest } = raw

const searchParams: AdminGetDraftOrdersParams = {
limit: pageSize,
offset: offset ? Number(offset) : 0,
status: status ? (status.split(",") as ["open" | "completed"]) : undefined,
created_at: created_at ? JSON.parse(created_at) : undefined,
updated_at: updated_at ? JSON.parse(updated_at) : undefined,
...rest,
}

return {
searchParams,
raw,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { DraftOrderListTable } from "./components/draft-order-list-table"

export const DraftOrderList = () => {
return (
<div className="flex flex-col gap-y-2">
<DraftOrderListTable />
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { DraftOrderList as Component } from "./draft-order-list"

This file was deleted.

This file was deleted.

Loading

0 comments on commit 78e5ec4

Please sign in to comment.