chore(dashboard): Cleanup Pricing domain (#7035)

**What**
- Adds missing translations
- Minor cleanup

**Note**
- The domain is still missing features that are supported in V1, but are currently not available in V2. The types are also all wrong, so will need to revisit after the pricing domain is revisited, types have been added, and missing features implemented.

CLOSES CORE-1901
This commit is contained in:
Kasper Fabricius Kristensen
2024-04-09 16:53:09 +02:00
committed by GitHub
parent e1a0960e20
commit 596faf2ad3
21 changed files with 134 additions and 59 deletions

View File

@@ -741,7 +741,20 @@
},
"pricing": {
"domain": "Pricing",
"deletePriceListWarning": "You are about to delete the price list {{name}}. This action cannot be undone.",
"create": {
"header": "Create Price List",
"hint": "Create a new price list to manage the prices of your products."
},
"edit": {
"header": "Edit Price List"
},
"configuration": {
"header": "Configuration",
"editHeader": "Edit Price List Configuration"
},
"warnings": {
"delete": "You are about to delete the price list {{name}}. This action cannot be undone."
},
"status": {
"draft": "Draft",
"expired": "Expired",
@@ -752,15 +765,6 @@
"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."
@@ -768,6 +772,25 @@
"prices": {
"addPrices": "Add prices",
"editPrices": "Edit prices"
},
"table": {
"pricesHeader": "Prices"
},
"fields": {
"typeHint": "Choose the type of price you want to create.",
"saleTypeHint": "Sale prices are temporary price changes for products.",
"overrideTypeHint": "Overrides are usually used to create customer-specific prices.",
"startDateLabel": "Price list has a start date?",
"startDateHint": "Schedule the price list to activate in the future.",
"endDateLabel": "Price list has an expiry date?",
"endDateHint": "Schedule the price list to deactivate in the future.",
"customerAvailabilityLabel": "Customer availability",
"customerAvailabilityHint": "Choose which customer groups the price list should be applied to.",
"customerAvailabilityNoSelectionLabel": "No customer groups selected",
"priceOverridesLabel": "Price overrides"
},
"actions": {
"addCustomerGroups": "Add customer groups"
}
},
"profile": {

View File

@@ -2,14 +2,15 @@ import { Text } from "@medusajs/ui"
import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react"
import { CustomerGroupDTO } from "@medusajs/types"
import { AdminCustomerGroupResponse } from "@medusajs/types"
import {
CreatedAtCell,
CreatedAtHeader,
} from "../../../components/table/table-cells/common/created-at-cell"
import { NameHeader } from "../../../components/table/table-cells/common/name-cell"
const columnHelper = createColumnHelper<CustomerGroupDTO>()
const columnHelper =
createColumnHelper<AdminCustomerGroupResponse["customer_group"]>()
export const useCustomerGroupTableColumns = () => {
return useMemo(

View File

@@ -300,7 +300,7 @@ export const v2Routes: RouteObject[] = [
{
path: "products/add",
lazy: () =>
import("../../v2-routes/pricing/pricing-products-add"),
import("../../v2-routes/pricing/pricing-products"),
},
{
path: "products/edit",

View File

@@ -91,10 +91,10 @@ export const PriceListConfigurationForm = ({
<div className="grid grid-cols-[1fr_32px] gap-4">
<div>
<Text size="small" leading="compact" weight="plus">
Price list has a start date?
{t("pricing.fields.startDateLabel")}
</Text>
<Text size="small" className="text-ui-fg-subtle">
Schedule the price list to activate in the future.
{t("pricing.fields.startDateHint")}
</Text>
</div>
<Collapsible.Trigger asChild>
@@ -148,10 +148,10 @@ export const PriceListConfigurationForm = ({
<div className="grid grid-cols-[1fr_32px] gap-4">
<div>
<Text size="small" leading="compact" weight="plus">
Price list has an end date?
{t("pricing.fields.endDateLabel")}
</Text>
<Text size="small" className="text-ui-fg-subtle">
Schedule the price list to deactivate in the future.
{t("pricing.fields.endDateHint")}
</Text>
</div>
<Collapsible.Trigger asChild>

View File

@@ -20,7 +20,7 @@ export const PricingConfiguration = () => {
return (
<RouteDrawer>
<RouteDrawer.Header>
<Heading>{t("pricing.settings.editPriceListTitle")}</Heading>
<Heading>{t("pricing.configuration.editHeader")}</Heading>
</RouteDrawer.Header>
{ready && <PriceListConfigurationForm priceList={price_list} />}
</RouteDrawer>

View File

@@ -84,7 +84,7 @@ export const PricingCreateForm = () => {
for (const [currencyCode, currencyPrice] of Object.entries(
currency_prices
)) {
if (!currencyPrice) {
if (!currencyPrice?.amount) {
continue
}

View File

@@ -14,7 +14,7 @@ import { useFieldArray, type UseFormReturn } from "react-hook-form"
import { useTranslation } from "react-i18next"
import { XMarkMini } from "@medusajs/icons"
import { CustomerGroupDTO } from "@medusajs/types"
import { AdminCustomerGroupResponse } from "@medusajs/types"
import { keepPreviousData } from "@tanstack/react-query"
import {
OnChangeFn,
@@ -89,9 +89,9 @@ export const PricingDetailsForm = ({ form }: PricingDetailsFormProps) => {
<div className="flex flex-1 flex-col items-center overflow-y-auto">
<div className="flex w-full max-w-[720px] flex-col gap-y-8 px-2 py-16">
<div>
<Heading>Create Price List</Heading>
<Heading>{t("pricing.create.header")}</Heading>
<Text size="small" className="text-ui-fg-subtle">
Create a new price list to manage the prices of your products.
{t("pricing.create.hint")}
</Text>
</div>
<Form.Field
@@ -103,9 +103,7 @@ export const PricingDetailsForm = ({ form }: PricingDetailsFormProps) => {
<div className="flex flex-col gap-y-4">
<div>
<Form.Label>{t("fields.type")}</Form.Label>
<Form.Hint>
Choose the type of price list you want to create.
</Form.Hint>
<Form.Hint>{t("pricing.fields.typeHint")}</Form.Hint>
</div>
<Form.Control>
<RadioGroup
@@ -189,11 +187,20 @@ export const PricingDetailsForm = ({ form }: PricingDetailsFormProps) => {
>
<div className="grid grid-cols-[1fr_32px] gap-4">
<div>
<Text size="small" leading="compact" weight="plus">
Price list has a start date?
</Text>
<div className="flex items-center gap-x-1">
<Text size="small" leading="compact" weight="plus">
{t("pricing.fields.startDateLabel")}
</Text>
<Text
size="small"
leading="compact"
className="text-ui-fg-muted"
>
({t("fields.optional")})
</Text>
</div>
<Text size="small" className="text-ui-fg-subtle">
Schedule the price list to activate in the future.
{t("pricing.fields.startDateHint")}
</Text>
</div>
<Collapsible.Trigger asChild>
@@ -246,11 +253,20 @@ export const PricingDetailsForm = ({ form }: PricingDetailsFormProps) => {
>
<div className="grid grid-cols-[1fr_32px] gap-4">
<div>
<Text size="small" leading="compact" weight="plus">
Price list has an end date?
</Text>
<div className="flex items-center gap-x-1">
<Text size="small" leading="compact" weight="plus">
{t("pricing.fields.endDateLabel")}
</Text>
<Text
size="small"
leading="compact"
className="text-ui-fg-muted"
>
({t("fields.optional")})
</Text>
</div>
<Text size="small" className="text-ui-fg-subtle">
Schedule the price list to deactivate in the future.
{t("pricing.fields.endDateHint")}
</Text>
</div>
<Collapsible.Trigger asChild>
@@ -292,11 +308,10 @@ export const PricingDetailsForm = ({ form }: PricingDetailsFormProps) => {
<div className="grid grid-cols-[1fr_32px] items-start gap-4">
<div>
<Form.Label optional>
Customer availability
{t("pricing.fields.customerAvailabilityLabel")}
</Form.Label>
<Form.Hint>
Specify which customer groups the price overrides
should apply for.
{t("pricing.fields.customerAvailabilityHint")}
</Form.Hint>
</div>
<Form.Control>
@@ -342,7 +357,9 @@ export const PricingDetailsForm = ({ form }: PricingDetailsFormProps) => {
leading="compact"
className="text-ui-fg-muted"
>
No customer groups selected.
{t(
"pricing.fields.customerAvailabilityNoSelectionLabel"
)}
</Text>
</div>
)}
@@ -353,7 +370,7 @@ export const PricingDetailsForm = ({ form }: PricingDetailsFormProps) => {
type="button"
onClick={handleOpenDrawer}
>
Add customer groups
{t("pricing.actions.addCustomerGroups")}
</Button>
</div>
</div>
@@ -424,7 +441,7 @@ const CustomerGroupDrawer = ({
const newCustomerGroups =
customer_groups
?.filter((cg) => newIds.includes(cg.id))
.map((cg) => ({ id: cg.id, name: cg.name })) || []
.map((cg) => ({ id: cg.id, name: cg.name! })) || []
const filteredIntermediate = intermediate.filter(
(cg) => !removedIds.includes(cg.id)
@@ -494,7 +511,8 @@ const CustomerGroupDrawer = ({
)
}
const columnHelper = createColumnHelper<CustomerGroupDTO>()
const columnHelper =
createColumnHelper<AdminCustomerGroupResponse["customer_group"]>()
const useColumns = () => {
const base = useCustomerGroupTableColumns()

View File

@@ -14,7 +14,8 @@ import { useProductTableFilters } from "../../../../../hooks/table/filters/use-p
import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { ExtendedProductDTO } from "../../../../../types/api-responses"
import { PricingCreateSchemaType, PricingProductsRecordType } from "./schema"
import { PricingProductsRecordType } from "../../../common/schemas"
import { PricingCreateSchemaType } from "./schema"
type PricingProductsFormProps = {
form: UseFormReturn<PricingCreateSchemaType>

View File

@@ -22,7 +22,7 @@ export const PricingConfigurationSection = ({
return (
<Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4">
<Heading level="h2">{t("fields.configurations")}</Heading>
<Heading level="h2">{t("pricing.configuration.header")}</Heading>
<ActionMenu
groups={[
{

View File

@@ -3,6 +3,7 @@ import { PriceListDTO } from "@medusajs/types"
import { Container, Heading, StatusBadge, Text, usePrompt } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { useNavigate } from "react-router-dom"
import { ActionMenu } from "../../../../../components/common/action-menu"
import { useDeletePriceList } from "../../../../../hooks/api/price-lists"
import { getPriceListStatus } from "../../../common/utils"
@@ -27,7 +28,7 @@ export const PricingGeneralSection = ({
const handleDelete = async () => {
const res = await prompt({
title: t("general.areYouSure"),
description: t("pricing.deletePriceListWarning", {
description: t("pricing.warnings.delete", {
name: priceList.title,
}),
confirmText: t("actions.delete"),
@@ -98,7 +99,7 @@ export const PricingGeneralSection = ({
</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")}
{t("pricing.fields.priceOverridesLabel")}
</Text>
<Text size="small" className="text-pretty">
{overrideCount || "-"}

View File

@@ -159,7 +159,9 @@ const ProductRowAction = ({ product }: { product: ExtendedProductDTO }) => {
icon: <Trash />,
label: t("actions.remove"),
onClick: () => {
console.log("Not implemented yet.")
console.log(
`Removing prices for ${product.id}. Not implemented yet.`
)
},
},
],

View File

@@ -60,19 +60,19 @@ export const EditPriceListForm = ({ priceList }: EditPriceListFormProps) => {
<Form.Item>
<div>
<Form.Label>{t("fields.type")}</Form.Label>
<Form.Hint>{t("pricing.settings.typeHint")}</Form.Hint>
<Form.Hint>{t("pricing.fields.typeHint")}</Form.Hint>
</div>
<Form.Control>
<RadioGroup {...field} onValueChange={onChange}>
<RadioGroup.ChoiceBox
value={PriceListType.SALE}
label={t("pricing.type.sale")}
description={t("pricing.settings.saleTypeHint")}
description={t("pricing.fields.saleTypeHint")}
/>
<RadioGroup.ChoiceBox
value={PriceListType.OVERRIDE}
label={t("pricing.type.override")}
description={t("pricing.settings.overrideTypeHint")}
description={t("pricing.fields.overrideTypeHint")}
/>
</RadioGroup>
</Form.Control>

View File

@@ -20,7 +20,7 @@ export const PricingEdit = () => {
return (
<RouteDrawer>
<RouteDrawer.Header>
<Heading>{t("pricing.settings.editPriceListTitle")}</Heading>
<Heading>{t("pricing.edit.header")}</Heading>
</RouteDrawer.Header>
{ready && <EditPriceListForm priceList={price_list} />}
</RouteDrawer>

View File

@@ -6,6 +6,7 @@ import { DataTable } from "../../../../../components/table/data-table"
import { usePriceLists } from "../../../../../hooks/api/price-lists"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { usePricingTableColumns } from "./use-pricing-table-columns"
import { usePricingTableFilters } from "./use-pricing-table-filters"
import { usePricingTableQuery } from "./use-pricing-table-query"
const PAGE_SIZE = 20
@@ -18,7 +19,7 @@ export const PricingListTable = () => {
})
const { price_lists, count, isLoading, isError, error } = usePriceLists(
// {
// ...searchParams, // The query params are not implemented, and any search params other than expand and fields will throw an error
// ...searchParams, // TODO: Query params are not currently supported by the API.
// },
undefined,
{
@@ -26,6 +27,7 @@ export const PricingListTable = () => {
}
)
const filters = usePricingTableFilters()
const columns = usePricingTableColumns()
const { table } = useDataTable({
@@ -53,6 +55,8 @@ export const PricingListTable = () => {
table={table}
columns={columns}
count={count}
filters={filters}
orderBy={["name", "status", "created_at", "updated_at"]}
queryObject={raw}
pageSize={PAGE_SIZE}
navigateTo={(row) => row.original.id}

View File

@@ -3,6 +3,10 @@ import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react"
import { useTranslation } from "react-i18next"
import { StatusCell } from "../../../../../components/table/table-cells/common/status-cell"
import {
TextCell,
TextHeader,
} from "../../../../../components/table/table-cells/common/text-cell"
import { getPriceListStatus } from "../../../common/utils"
import { PricingTableActions } from "./pricing-table-actions"
@@ -14,7 +18,7 @@ export const usePricingTableColumns = () => {
return useMemo(
() => [
columnHelper.accessor("title", {
header: t("fields.name"),
header: () => <TextHeader text={t("fields.name")} />,
cell: (info) => info.getValue(),
}),
columnHelper.accessor("status", {
@@ -26,8 +30,8 @@ export const usePricingTableColumns = () => {
},
}),
columnHelper.accessor("prices", {
header: t("fields.prices"),
cell: (info) => info.getValue()?.length || "-",
header: t("pricing.table.pricesHeader"),
cell: (info) => <TextCell text={`${info.getValue()?.length || "-"}`} />,
}),
columnHelper.display({
id: "actions",

View File

@@ -0,0 +1,18 @@
import { useTranslation } from "react-i18next"
import { Filter } from "../../../../../components/table/data-table"
export const usePricingTableFilters = () => {
const { t } = useTranslation()
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 dateFilters
}

View File

@@ -1 +0,0 @@
export { PricingProductsAdd as Component } from "./pricing-products-add"

View File

@@ -1,5 +0,0 @@
import { RouteFocusModal } from "../../../components/route-modal"
export const PricingProductsAdd = () => {
return <RouteFocusModal></RouteFocusModal>
}

View File

@@ -0,0 +1 @@
export { PricingProducts as Component } from "./pricing-products"

View File

@@ -0,0 +1,5 @@
import { RouteFocusModal } from "../../../components/route-modal"
export const PricingProducts = () => {
return <RouteFocusModal>Not Implemented Yet</RouteFocusModal>
}

View File

@@ -7,6 +7,9 @@ export interface CustomerGroupResponse {
id: string
name: string | null
customers: CustomerResponse[]
metadata: Record<string, unknown> | null
created_at: string
updated_at: string
}
/**