Skip to content

Commit

Permalink
feat(medusa,dahsboard): Initial work on pricing domain (#6633)
Browse files Browse the repository at this point in the history
**What**
- Initial work on pricing domain.
- List page
- Details page
- Partial edit form
- Fixes admin/price-lists/:id/products endpoint to allow filtering products by multiple ids.

**Note**
Pushing this now as the current design need a bit of tweaking so we display all relevant data to users. Future PR will include completed Edit moda, Create modal, Edit prices modal and Add prices modal.
  • Loading branch information
kasperkristensen authored Mar 11, 2024
1 parent b8bedb8 commit e124762
Show file tree
Hide file tree
Showing 39 changed files with 1,192 additions and 82 deletions.
6 changes: 6 additions & 0 deletions .changeset/calm-singers-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@medusajs/client-types": patch
"@medusajs/medusa": patch
---

fix(medusa): Allows to filter price list products by multiple ids.
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,35 @@
}
},
"pricing": {
"domain": "Pricing"
"domain": "Pricing",
"deletePriceListWarning": "You are about to delete the price list {{name}}. This action cannot be undone.",
"status": {
"draft": "Draft",
"expired": "Expired",
"active": "Active",
"scheduled": "Scheduled"
},
"type": {
"sale": "Sale",
"override": "Override"
},
"settings": {
"typeHint": "Choose the type of price list you want to create.",
"saleTypeHint": "Sale prices are temporary price changes for products.",
"overrideTypeHint": "Overrides are usually used to create customer-specific prices.",
"editPriceListTitle": "Edit Price List",
"customerGroupsLabel": "Customer groups",
"priceOverridesLabel": "Price overrides",
"taxInclusivePricingHint": "When enabled all prices in the price list will be tax inclusive."
},
"products": {
"deleteProductsPricesWarning_one": "You are about to delete {{count}} product price. This action cannot be undone.",
"deleteProductsPricesWarning_other": "You are about to delete {{count}} product prices. This action cannot be undone."
},
"prices": {
"addPrices": "Add prices",
"editPrices": "Edit prices"
}
},
"profile": {
"domain": "Profile",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,14 +487,13 @@ export const DataGridRoot = <
}, [handleMouseUp, handleCopy, handlePaste, handleCommandHistory])

return (
<div className="overflow-hidden">
<div className="border-b p-4"></div>
<div className="size-full overflow-hidden">
<div
ref={tableContainerRef}
style={{
overflow: "auto",
position: "relative",
height: "600px",
height: "100%",
userSelect: isSelecting || isDragging ? "none" : "auto",
}}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,9 @@ export const DataGrid = <TData, TFieldValues extends FieldValues = any>({
isLoading,
...props
}: DataGridProps<TData, TFieldValues>) => {
return (
<div>
{isLoading ? (
<DataGridSkeleton columns={props.columns} rowCount={10} />
) : (
<DataGridRoot {...props} />
)}
</div>
return isLoading ? (
<DataGridSkeleton columns={props.columns} rowCount={10} />
) : (
<DataGridRoot {...props} />
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const useProductTableQuery = ({
"tags",
"type_id",
"status",
"id",
],
prefix
)
Expand Down
20 changes: 0 additions & 20 deletions packages/admin-next/dashboard/src/hooks/use-form-prompt.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -405,12 +405,34 @@ const router = createBrowserRouter([
},
children: [
{
index: true,
lazy: () => import("../../routes/pricing/list"),
path: "",
lazy: () => import("../../routes/pricing/pricing-list"),
children: [
// {
// path: "create",
// lazy: () => import("../../routes/pricing/pricing-create"),
// },
],
},
{
path: ":id",
lazy: () => import("../../routes/pricing/details"),
lazy: () => import("../../routes/pricing/pricing-detail"),
children: [
{
path: "edit",
lazy: () => import("../../routes/pricing/pricing-edit"),
},
{
path: "products/add",
lazy: () =>
import("../../routes/pricing/pricing-products-add"),
},
{
path: "products/edit",
lazy: () =>
import("../../routes/pricing/pricing-products-edit"),
},
],
},
],
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Re-implementation of enum from `@medusajs/medusa` as it cannot be imported
*/
export enum PriceListStatus {
ACTIVE = "active",
DRAFT = "draft",
}

/**
* Re-implementation of enum from `@medusajs/medusa` as it cannot be imported
*/
export enum PriceListType {
SALE = "sale",
OVERRIDE = "override",
}
48 changes: 48 additions & 0 deletions packages/admin-next/dashboard/src/routes/pricing/common/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { PriceList } from "@medusajs/medusa"
import { TFunction } from "i18next"
import { PriceListStatus } from "./constants"

const getValues = (priceList: PriceList) => {
const startsAt = priceList.starts_at
const endsAt = priceList.ends_at

const isExpired = endsAt ? new Date(endsAt) < new Date() : false
const isScheduled = startsAt ? new Date(startsAt) > new Date() : false
const isDraft = priceList.status === PriceListStatus.DRAFT

return {
isExpired,
isScheduled,
isDraft,
}
}

export const getPriceListStatus = (
t: TFunction<"translation">,
priceList: PriceList
) => {
const { isExpired, isScheduled, isDraft } = getValues(priceList)

let text = t("pricing.status.active")
let color: "red" | "grey" | "orange" | "green" = "green"

if (isScheduled) {
color = "orange"
text = t("pricing.status.scheduled")
}

if (isDraft) {
color = "grey"
text = t("pricing.status.draft")
}

if (isExpired) {
color = "red"
text = t("pricing.status.expired")
}

return {
color,
text,
}
}

This file was deleted.

This file was deleted.

This file was deleted.

11 changes: 0 additions & 11 deletions packages/admin-next/dashboard/src/routes/pricing/list/list.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./pricing-general-section"
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { PencilSquare, Trash } from "@medusajs/icons"
import { PriceList } from "@medusajs/medusa"
import {
Container,
Heading,
StatusBadge,
Text,
Tooltip,
usePrompt,
} from "@medusajs/ui"
import { useAdminDeletePriceList } from "medusa-react"
import { useTranslation } from "react-i18next"
import { useNavigate } from "react-router-dom"
import { ActionMenu } from "../../../../../components/common/action-menu"
import { getPriceListStatus } from "../../../common/utils"

type PricingGeneralSectionProps = {
priceList: PriceList
}

export const PricingGeneralSection = ({
priceList,
}: PricingGeneralSectionProps) => {
const { t } = useTranslation()
const navigate = useNavigate()
const prompt = usePrompt()

const { mutateAsync } = useAdminDeletePriceList(priceList.id)

const overrideCount = priceList.prices?.length || 0
const firstCustomerGroups = priceList.customer_groups?.slice(0, 3)
const remainingCustomerGroups = priceList.customer_groups?.slice(3)

const { color, text } = getPriceListStatus(t, priceList)

const handleDelete = async () => {
const res = await prompt({
title: t("general.areYouSure"),
description: t("pricing.deletePriceListWarning", {
name: priceList.name,
}),
confirmText: t("actions.delete"),
cancelText: t("actions.cancel"),
})

if (!res) {
return
}

await mutateAsync(undefined, {
onSuccess: () => {
navigate("..", { replace: true })
},
})
}

const type =
priceList.type === "sale"
? t("pricing.type.sale")
: t("pricing.type.override")

return (
<Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4">
<Heading>{priceList.name}</Heading>
<div className="flex items-center gap-x-4">
<StatusBadge color={color}>{text}</StatusBadge>
<ActionMenu
groups={[
{
actions: [
{
label: t("actions.edit"),
to: "edit",
icon: <PencilSquare />,
},
],
},
{
actions: [
{
label: t("actions.delete"),
onClick: handleDelete,
icon: <Trash />,
},
],
},
]}
/>
</div>
</div>
<div className="text-ui-fg-subtle grid grid-cols-2 items-center px-6 py-4">
<Text leading="compact" size="small" weight="plus">
{t("fields.type")}
</Text>
<Text size="small" className="text-pretty">
{type}
</Text>
</div>
<div className="text-ui-fg-subtle grid grid-cols-2 items-center px-6 py-4">
<Text leading="compact" size="small" weight="plus">
{t("fields.description")}
</Text>
<Text size="small" className="text-pretty">
{priceList.description}
</Text>
</div>
<div className="text-ui-fg-subtle grid grid-cols-2 items-center px-6 py-4">
<Text leading="compact" size="small" weight="plus">
{t("pricing.settings.customerGroupsLabel")}
</Text>
<Text size="small" className="text-pretty">
<span>
{firstCustomerGroups.length > 0
? firstCustomerGroups.join(", ")
: "-"}
</span>
{remainingCustomerGroups.length > 0 && (
<Tooltip
content={
<ul>
{remainingCustomerGroups.map((cg) => (
<li key={cg.id}>{cg.name}</li>
))}
</ul>
}
>
<span className="text-ui-fg-muted">
{" "}
{t("general.plusCountMore", {
count: remainingCustomerGroups.length,
})}
</span>
</Tooltip>
)}
</Text>
</div>
<div className="text-ui-fg-subtle grid grid-cols-2 items-center px-6 py-4">
<Text leading="compact" size="small" weight="plus">
{t("pricing.settings.priceOverridesLabel")}
</Text>
<Text size="small" className="text-pretty">
{overrideCount || "-"}
</Text>
</div>
</Container>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./pricing-product-section"
Loading

0 comments on commit e124762

Please sign in to comment.