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: