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:
committed by
GitHub
parent
e1a0960e20
commit
596faf2ad3
@@ -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": {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -84,7 +84,7 @@ export const PricingCreateForm = () => {
|
||||
for (const [currencyCode, currencyPrice] of Object.entries(
|
||||
currency_prices
|
||||
)) {
|
||||
if (!currencyPrice) {
|
||||
if (!currencyPrice?.amount) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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={[
|
||||
{
|
||||
|
||||
@@ -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 || "-"}
|
||||
|
||||
@@ -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.`
|
||||
)
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { PricingProductsAdd as Component } from "./pricing-products-add"
|
||||
@@ -1,5 +0,0 @@
|
||||
import { RouteFocusModal } from "../../../components/route-modal"
|
||||
|
||||
export const PricingProductsAdd = () => {
|
||||
return <RouteFocusModal></RouteFocusModal>
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { PricingProducts as Component } from "./pricing-products"
|
||||
@@ -0,0 +1,5 @@
|
||||
import { RouteFocusModal } from "../../../components/route-modal"
|
||||
|
||||
export const PricingProducts = () => {
|
||||
return <RouteFocusModal>Not Implemented Yet</RouteFocusModal>
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user