diff --git a/.changeset/many-bees-own.md b/.changeset/many-bees-own.md
new file mode 100644
index 0000000000..29637d8cfa
--- /dev/null
+++ b/.changeset/many-bees-own.md
@@ -0,0 +1,6 @@
+---
+"@medusajs/admin-ui": patch
+"@medusajs/admin": patch
+---
+
+fix(admin-ui): minor bugs throughout Price List domain plus improved form validation
diff --git a/packages/admin-ui/package.json b/packages/admin-ui/package.json
index 67758697ac..5288c45461 100644
--- a/packages/admin-ui/package.json
+++ b/packages/admin-ui/package.json
@@ -70,7 +70,7 @@
"i18next-browser-languagedetector": "^7.0.1",
"i18next-http-backend": "^2.2.1",
"md5": "^2.3.0",
- "medusa-react": "*",
+ "medusa-react": "^9.0.7",
"mini-css-extract-plugin": "^2.7.6",
"moment": "^2.29.4",
"path-browserify": "^1.0.1",
@@ -118,8 +118,8 @@
},
"devDependencies": {
"@babel/types": "7.22.5",
- "@medusajs/medusa": "*",
- "@medusajs/types": "*",
+ "@medusajs/medusa": "^1.17.1",
+ "@medusajs/types": "^1.11.3",
"@types/pluralize": "^0.0.29",
"@types/react": "^18.0.27",
"@types/react-datepicker": "^4.10.0",
diff --git a/packages/admin-ui/ui/public/locales/en/translation.json b/packages/admin-ui/ui/public/locales/en/translation.json
index d4a28e9e31..f46e9330bf 100644
--- a/packages/admin-ui/ui/public/locales/en/translation.json
+++ b/packages/admin-ui/ui/public/locales/en/translation.json
@@ -1423,6 +1423,9 @@
"price-list-new-form-prompt-title": "Are you sure?",
"price-list-new-form-prompt-exit-description": "You have unsaved changes, are you sure you want to exit?",
"price-list-new-form-prompt-back-description": "You have unsaved changes, are you sure you want to go back?",
+ "price-list-add-products-modal-no-prices-error": "Please assign prices for at least one product.",
+ "price-list-add-products-modal-missing-prices-title": "Incomplete price list",
+ "price-list-add-products-modal-missing-prices-description": "Prices have not been assigned to all of your chosen products. Would you like to continue?",
"price-list-add-products-modal-success-title": "New prices added",
"price-list-add-products-modal-success-message": "The new prices have been added to the price list.",
"price-list-add-products-modal-error-title": "An error occurred",
@@ -1488,7 +1491,7 @@
"price-list-details-form-dates-starts-at-label": "Start date",
"price-list-details-form-ends-at-heading": "Price list has an expiry date?",
"price-list-details-form-ends-at-description": "Schedule the price overrides to deactivate in the future.",
- "price-list-details-form-ends-at-label": "End date",
+ "price-list-details-form-ends-at-label": "Expiry date",
"price-list-details-form-customer-groups-name": "Name",
"price-list-details-form-customer-groups-members": "Members",
"price-list-details-form-customer-groups-error": "An error occurred while loading customer groups. Reload the page and try again. If the issue persists, try again later.",
@@ -1514,7 +1517,7 @@
"price-list-product-prices-form-column-visibility-regions-label": "Regions",
"price-list-product-prices-form-column-product-label": "Product",
"price-list-product-prices-form-column-currencies-price-label": "Price {{code}}",
- "price-list-product-prices-form-column-regions-price-label": "Price {{code}}",
+ "price-list-product-prices-form-column-regions-price-label": "Price {{name}} ({{code}})",
"price-list-products-form-select-all": "Select all products on the current page",
"price-list-products-form-select-row": "Select row",
"price-list-products-form-product-label": "Product",
@@ -1530,6 +1533,9 @@
"price-list-products-form-no-products": "No products found.",
"price-list-products-form-heading": "Choose products",
"price-list-products-form-search-placeholder": "Search",
+ "price-list-new-form-no-prices-error": "Please set prices for at least one product.",
+ "price-list-new-form-missing-prices-title": "Incomplete price list",
+ "price-list-new-products-modal-missing-prices-description": "Prices have not been assigned to all of your chosen products. Would you like to proceed?",
"price-list-new-form-notification-success-title": "Price list created",
"price-list-new-form-notification-success-message": "Successfully created price list",
"price-list-new-form-notification-error-title": "An error occurred",
diff --git a/packages/admin-ui/ui/src/domain/pricing/edit/details/details-section.tsx b/packages/admin-ui/ui/src/domain/pricing/edit/details/details-section.tsx
index 2ef53a77f0..0eb8fb62ed 100644
--- a/packages/admin-ui/ui/src/domain/pricing/edit/details/details-section.tsx
+++ b/packages/admin-ui/ui/src/domain/pricing/edit/details/details-section.tsx
@@ -69,6 +69,7 @@ const PriceListDetailsSection = ({
name,
}
),
+ verificationText: name,
confirmText,
cancelText,
})
diff --git a/packages/admin-ui/ui/src/domain/pricing/edit/edit.tsx b/packages/admin-ui/ui/src/domain/pricing/edit/edit.tsx
index 654c7b9ca7..c7393a6ac8 100644
--- a/packages/admin-ui/ui/src/domain/pricing/edit/edit.tsx
+++ b/packages/admin-ui/ui/src/domain/pricing/edit/edit.tsx
@@ -48,7 +48,7 @@ const PriceListEdit = () => {
return (
<>
- {getWidgets("product.details.before").map((w, i) => {
+ {getWidgets("price_list.details.before").map((w, i) => {
return (
{
})}
- {getWidgets("product.details.after").map((w, i) => {
+ {getWidgets("price_list.details.after").map((w, i) => {
return (
{
onOpenChange(false)
setTab(Tab.PRODUCTS)
+ setSelectedIds([])
setStatus({
[Tab.PRODUCTS]: "not-started",
[Tab.PRICES]: "not-started",
@@ -205,6 +207,42 @@ const AddProductsModal = ({
const onSubmit = handleSubmit(async (data) => {
const prices: PricePayload[] = []
+ const productPriceKeys = Object.keys(data.prices.products)
+ const productIds = data.products.ids
+
+ if (!productPriceKeys.length || !data.prices.products) {
+ setError("prices.products", {
+ type: "manual",
+ message: t(
+ "price-list-add-products-modal-no-prices-error",
+ "Please assign prices for at least one product."
+ ) as string,
+ })
+
+ return
+ }
+
+ const missingProducts = productIds.filter(
+ (id) => !productPriceKeys.includes(id)
+ )
+
+ if (missingProducts.length > 0) {
+ const res = await prompt({
+ title: t(
+ "price-list-add-products-modal-missing-prices-title",
+ "Incomplete price list"
+ ),
+ description: t(
+ "price-list-add-products-modal-missing-prices-description",
+ "Prices have not been assigned to all of your chosen products. Would you like to continue?"
+ ),
+ })
+
+ if (!res) {
+ return
+ }
+ }
+
for (const productId of Object.keys(data.prices.products)) {
const product = data.prices.products[productId]
@@ -533,6 +571,7 @@ const AddProductsModal = ({
{
return (
- {t("price-list-details-form-ends-at-label", "End date")}
+ {t(
+ "price-list-details-form-ends-at-label",
+ "Expiry date"
+ )}
@@ -23,7 +24,12 @@ const PriceListPricesForm = ({
productIds,
priceListId,
}: PriceListPricesFormProps) => {
- const { path, getValues } = form
+ const {
+ control,
+ path,
+ getValues,
+ formState: { isDirty },
+ } = form
const { t } = useTranslation()
@@ -87,9 +93,24 @@ const PriceListPricesForm = ({
-
- {t("price-list-prices-form-heading", "Edit prices")}
-
+
+
+ {t("price-list-prices-form-heading", "Edit prices")}
+
+ {isDirty && (
+
{
+ return (
+
+
+
+ )
+ }}
+ />
+ )}
+
setFilters({})}
diff --git a/packages/admin-ui/ui/src/domain/pricing/forms/price-list-product-prices-form/price-list-product-prices-form.tsx b/packages/admin-ui/ui/src/domain/pricing/forms/price-list-product-prices-form/price-list-product-prices-form.tsx
index 085fd402af..cce5be535f 100644
--- a/packages/admin-ui/ui/src/domain/pricing/forms/price-list-product-prices-form/price-list-product-prices-form.tsx
+++ b/packages/admin-ui/ui/src/domain/pricing/forms/price-list-product-prices-form/price-list-product-prices-form.tsx
@@ -1565,8 +1565,9 @@ const PriceListProductPricesForm = ({
{t(
"price-list-product-prices-form-column-regions-price-label",
- "Price {{code}}",
+ "Price {{name}} ({{code}})",
{
+ name: region.name,
code: region.currency_code.toUpperCase(),
}
)}
diff --git a/packages/admin-ui/ui/src/domain/pricing/new/new.tsx b/packages/admin-ui/ui/src/domain/pricing/new/new.tsx
index 082fc77aa2..94e453b8e8 100644
--- a/packages/admin-ui/ui/src/domain/pricing/new/new.tsx
+++ b/packages/admin-ui/ui/src/domain/pricing/new/new.tsx
@@ -132,6 +132,7 @@ const PriceListNew = () => {
reset,
getValues,
setValue,
+ setError,
handleSubmit,
formState: { isDirty },
} = form
@@ -163,6 +164,7 @@ const PriceListNew = () => {
const onCloseModal = React.useCallback(() => {
setOpen(false)
setTab(Tab.DETAILS)
+ setSelectedIds([])
setStatus({
[Tab.DETAILS]: "not-started",
[Tab.PRODUCTS]: "not-started",
@@ -228,6 +230,42 @@ const PriceListNew = () => {
await handleSubmit(async (data) => {
const prices: PricePayload[] = []
+ const productPriceKeys = Object.keys(data.prices.products)
+ const productIds = data.products.ids
+
+ if (!productPriceKeys.length || !data.prices.products) {
+ setError("prices.products", {
+ type: "manual",
+ message: t(
+ "price-list-new-form-no-prices-error",
+ "Please set prices for at least one product."
+ ) as string,
+ })
+
+ return
+ }
+
+ const missingProducts = productIds.filter(
+ (id) => !productPriceKeys.includes(id)
+ )
+
+ if (missingProducts.length > 0) {
+ const res = await prompt({
+ title: t(
+ "price-list-new-form-missing-prices-title",
+ "Incomplete price list"
+ ),
+ description: t(
+ "price-list-new-products-modal-missing-prices-description",
+ "Prices have not been assigned to all of your chosen products. Would you like to proceed?"
+ ),
+ })
+
+ if (!res) {
+ return
+ }
+ }
+
/**
* Loop through all the products and variants
* and create a payload for each price.
@@ -348,6 +386,8 @@ const PriceListNew = () => {
mutateAsync,
notification,
onCloseModal,
+ setError,
+ prompt,
t,
isTaxInclPricesEnabled,
regions,
diff --git a/packages/admin-ui/ui/src/domain/pricing/overview/overview.tsx b/packages/admin-ui/ui/src/domain/pricing/overview/overview.tsx
index 089e1ab037..48d37ba5d7 100644
--- a/packages/admin-ui/ui/src/domain/pricing/overview/overview.tsx
+++ b/packages/admin-ui/ui/src/domain/pricing/overview/overview.tsx
@@ -384,7 +384,9 @@ const PriceListTableRowActions = ({ row }: PriceListTableRowActionsProps) => {
const navigate = useNavigate()
- const handleDelete = async () => {
+ const handleDelete = async (e: React.MouseEvent) => {
+ e.stopPropagation()
+
const response = await prompt({
title: "Are you sure?",
description: "This will permanently delete the price list",
diff --git a/yarn.lock b/yarn.lock
index b3b4bdd5a5..801f81ed35 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6268,8 +6268,8 @@ __metadata:
"@hookform/error-message": ^2.0.1
"@hookform/resolvers": ^3.3.1
"@medusajs/icons": 1.1.0
- "@medusajs/medusa": "*"
- "@medusajs/types": "*"
+ "@medusajs/medusa": ^1.17.1
+ "@medusajs/types": ^1.11.3
"@medusajs/ui": ^2.2.0
"@medusajs/ui-preset": 1.0.2
"@pmmmwh/react-refresh-webpack-plugin": ^0.5.10
@@ -6311,7 +6311,7 @@ __metadata:
i18next-parser: ^8.0.0
jest: 25.5.4
md5: ^2.3.0
- medusa-react: "*"
+ medusa-react: ^9.0.7
mini-css-extract-plugin: ^2.7.6
moment: ^2.29.4
path-browserify: ^1.0.1
@@ -6628,7 +6628,7 @@ __metadata:
languageName: unknown
linkType: soft
-"@medusajs/medusa@*, @medusajs/medusa@^1.12.1, @medusajs/medusa@^1.12.2, @medusajs/medusa@^1.12.3, @medusajs/medusa@^1.15.0, @medusajs/medusa@^1.15.1, @medusajs/medusa@^1.17.0, @medusajs/medusa@^1.17.1, @medusajs/medusa@workspace:*, @medusajs/medusa@workspace:packages/medusa":
+"@medusajs/medusa@^1.12.1, @medusajs/medusa@^1.12.2, @medusajs/medusa@^1.12.3, @medusajs/medusa@^1.15.0, @medusajs/medusa@^1.15.1, @medusajs/medusa@^1.17.0, @medusajs/medusa@^1.17.1, @medusajs/medusa@workspace:*, @medusajs/medusa@workspace:packages/medusa":
version: 0.0.0-use.local
resolution: "@medusajs/medusa@workspace:packages/medusa"
dependencies:
@@ -6867,7 +6867,7 @@ __metadata:
languageName: unknown
linkType: soft
-"@medusajs/types@*, @medusajs/types@^1.10.0, @medusajs/types@^1.11.2, @medusajs/types@^1.11.3, @medusajs/types@^1.8.10, @medusajs/types@^1.8.8, @medusajs/types@workspace:^, @medusajs/types@workspace:packages/types":
+"@medusajs/types@^1.10.0, @medusajs/types@^1.11.2, @medusajs/types@^1.11.3, @medusajs/types@^1.8.10, @medusajs/types@^1.8.8, @medusajs/types@workspace:^, @medusajs/types@workspace:packages/types":
version: 0.0.0-use.local
resolution: "@medusajs/types@workspace:packages/types"
dependencies:
@@ -32499,7 +32499,7 @@ __metadata:
languageName: unknown
linkType: soft
-"medusa-react@*, medusa-react@^9.0.6, medusa-react@workspace:packages/medusa-react":
+"medusa-react@^9.0.6, medusa-react@^9.0.7, medusa-react@workspace:packages/medusa-react":
version: 0.0.0-use.local
resolution: "medusa-react@workspace:packages/medusa-react"
dependencies: