Fix(admin-ui, medusa): stock location fixes (#3395)
**What** - A series of minor fixes for admin-ui relating to managing stock locations: - make "create location" `primary` - add delete prompt when cancelling creation if information has been input - avoid clipping focus border on country select when creating a stock location - allow removals of sales channels from stock locations Fixes CORE-1191, CORE-1192, CORE-1190, CORE-1189
This commit is contained in:
6
.changeset/rich-flowers-decide.md
Normal file
6
.changeset/rich-flowers-decide.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@medusajs/admin-ui": patch
|
||||
"@medusajs/medusa": patch
|
||||
---
|
||||
|
||||
fix(admin-ui, medusa): Minor ui fixes relating to stock locations
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { useState } from "react"
|
||||
import useNotification from "../../hooks/use-notification"
|
||||
import { getErrorMessage } from "../../utils/error-messages"
|
||||
|
||||
import Button from "../fundamentals/button"
|
||||
import Modal from "../molecules/modal"
|
||||
import { getErrorMessage } from "../../utils/error-messages"
|
||||
import useNotification from "../../hooks/use-notification"
|
||||
|
||||
type DeletePromptProps = {
|
||||
heading?: string
|
||||
@@ -31,7 +32,11 @@ const DeletePrompt: React.FC<DeletePromptProps> = ({
|
||||
|
||||
setIsLoading(true)
|
||||
onDelete()
|
||||
.then(() => notification("Success", successText, "success"))
|
||||
.then(() => {
|
||||
if (successText) {
|
||||
notification("Success", successText, "success")
|
||||
}
|
||||
})
|
||||
.catch((err) => notification("Error", getErrorMessage(err), "error"))
|
||||
.finally(() => {
|
||||
setIsLoading(false)
|
||||
@@ -45,14 +50,14 @@ const DeletePrompt: React.FC<DeletePromptProps> = ({
|
||||
<Modal.Content>
|
||||
<div className="flex flex-col">
|
||||
<span className="inter-large-semibold">{heading}</span>
|
||||
<span className="inter-base-regular mt-1 text-grey-50">{text}</span>
|
||||
<span className="inter-base-regular text-grey-50 mt-1">{text}</span>
|
||||
</div>
|
||||
</Modal.Content>
|
||||
<Modal.Footer>
|
||||
<div className="flex w-full h-8 justify-end">
|
||||
<div className="flex h-8 w-full justify-end">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="mr-2 w-24 text-small justify-center"
|
||||
className="text-small min-w-24 mr-2 justify-center"
|
||||
size="small"
|
||||
onClick={handleClose}
|
||||
>
|
||||
@@ -61,7 +66,7 @@ const DeletePrompt: React.FC<DeletePromptProps> = ({
|
||||
<Button
|
||||
loading={isLoading}
|
||||
size="small"
|
||||
className="w-24 text-small justify-center"
|
||||
className="text-small w-24 justify-center"
|
||||
variant="nuclear"
|
||||
onClick={handleSubmit}
|
||||
disabled={isLoading}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { StockLocationExpandedDTO } from "@medusajs/medusa"
|
||||
import { SalesChannel, StockLocationExpandedDTO } from "@medusajs/medusa"
|
||||
import {
|
||||
useAdminAddLocationToSalesChannel,
|
||||
useAdminRemoveLocationFromSalesChannel,
|
||||
} from "medusa-react"
|
||||
|
||||
import Button from "../../../../../components/fundamentals/button"
|
||||
import useToggleState from "../../../../../hooks/use-toggle-state"
|
||||
import SalesChannelsModal from "../../../../products/components/sales-channels-modal"
|
||||
import useToggleState from "../../../../../hooks/use-toggle-state"
|
||||
|
||||
const EditSalesChannels = ({
|
||||
location,
|
||||
@@ -23,7 +24,7 @@ const EditSalesChannels = ({
|
||||
const { mutateAsync: removeLocationFromSalesChannel } =
|
||||
useAdminRemoveLocationFromSalesChannel()
|
||||
|
||||
const onSave = async (channels) => {
|
||||
const onSave = async (channels: SalesChannel[]) => {
|
||||
const existingChannels = location.sales_channels
|
||||
const channelsToRemove =
|
||||
existingChannels?.filter(
|
||||
|
||||
@@ -4,22 +4,25 @@ import {
|
||||
StockLocationAddressDTO,
|
||||
StockLocationAddressInput,
|
||||
} from "@medusajs/medusa"
|
||||
import GeneralForm, { GeneralFormType } from "../components/general-form"
|
||||
import {
|
||||
useAdminAddLocationToSalesChannel,
|
||||
useAdminCreateStockLocation,
|
||||
} from "medusa-react"
|
||||
import { useForm } from "react-hook-form"
|
||||
|
||||
import Accordion from "../../../../components/organisms/accordion"
|
||||
import AddressForm from "../components/address-form"
|
||||
import Button from "../../../../components/fundamentals/button"
|
||||
import CrossIcon from "../../../../components/fundamentals/icons/cross-icon"
|
||||
import DeletePrompt from "../../../../components/organisms/delete-prompt"
|
||||
import FocusModal from "../../../../components/molecules/modal/focus-modal"
|
||||
import Accordion from "../../../../components/organisms/accordion"
|
||||
import useNotification from "../../../../hooks/use-notification"
|
||||
import { useFeatureFlag } from "../../../../providers/feature-flag-provider"
|
||||
import SalesChannelsForm from "../components/sales-channels-form"
|
||||
import { getErrorMessage } from "../../../../utils/error-messages"
|
||||
import { nestedForm } from "../../../../utils/nested-form"
|
||||
import AddressForm from "../components/address-form"
|
||||
import GeneralForm, { GeneralFormType } from "../components/general-form"
|
||||
import SalesChannelsForm from "../components/sales-channels-form"
|
||||
import { useFeatureFlag } from "../../../../providers/feature-flag-provider"
|
||||
import { useForm } from "react-hook-form"
|
||||
import useNotification from "../../../../hooks/use-notification"
|
||||
import useToggleState from "../../../../hooks/use-toggle-state"
|
||||
|
||||
type NewLocationForm = {
|
||||
general: GeneralFormType
|
||||
@@ -43,7 +46,16 @@ const NewLocation = ({ onClose }: { onClose: () => void }) => {
|
||||
reValidateMode: "onBlur",
|
||||
mode: "onBlur",
|
||||
})
|
||||
const { handleSubmit, formState } = form
|
||||
const {
|
||||
handleSubmit,
|
||||
formState: { isDirty, isValid },
|
||||
} = form
|
||||
|
||||
const {
|
||||
state: isShowingClosePrompt,
|
||||
open: showClosePrompt,
|
||||
close: closeClosePrompt,
|
||||
} = useToggleState()
|
||||
|
||||
const notification = useNotification()
|
||||
const { isFeatureEnabled } = useFeatureFlag()
|
||||
@@ -58,6 +70,14 @@ const NewLocation = ({ onClose }: { onClose: () => void }) => {
|
||||
location_id: locationId,
|
||||
})
|
||||
|
||||
const handleClose = () => {
|
||||
if (!isDirty) {
|
||||
onClose()
|
||||
} else {
|
||||
showClosePrompt()
|
||||
}
|
||||
}
|
||||
|
||||
const onSubmit = () =>
|
||||
handleSubmit(async (data) => {
|
||||
const { locationPayload, salesChannelsPayload } = createPayload(data)
|
||||
@@ -89,8 +109,6 @@ const NewLocation = ({ onClose }: { onClose: () => void }) => {
|
||||
}
|
||||
})
|
||||
|
||||
const { isDirty, isValid } = formState
|
||||
|
||||
return (
|
||||
<form className="w-full">
|
||||
<FocusModal>
|
||||
@@ -100,14 +118,24 @@ const NewLocation = ({ onClose }: { onClose: () => void }) => {
|
||||
size="small"
|
||||
variant="ghost"
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
onClick={handleClose}
|
||||
>
|
||||
<CrossIcon size={20} />
|
||||
</Button>
|
||||
{isShowingClosePrompt && (
|
||||
<DeletePrompt
|
||||
heading="Are you sure you want to cancel with unsaved changes"
|
||||
confirmText="Yes, cancel"
|
||||
cancelText="No, continue creating"
|
||||
successText={undefined}
|
||||
handleClose={closeClosePrompt}
|
||||
onDelete={async () => onClose()}
|
||||
/>
|
||||
)}
|
||||
<div className="gap-x-small flex">
|
||||
<Button
|
||||
size="small"
|
||||
variant="secondary"
|
||||
variant="primary"
|
||||
type="button"
|
||||
disabled={!isDirty || !isValid}
|
||||
onClick={onSubmit()}
|
||||
@@ -131,7 +159,7 @@ const NewLocation = ({ onClose }: { onClose: () => void }) => {
|
||||
<p className="inter-base-regular text-grey-50">
|
||||
Specify the details about this location
|
||||
</p>
|
||||
<div className="mt-xlarge gap-y-xlarge flex flex-col">
|
||||
<div className="mt-xlarge gap-y-xlarge flex flex-col pb-0.5">
|
||||
<GeneralForm form={nestedForm(form, "general")} />
|
||||
<AddressForm form={nestedForm(form, "address")} />
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { IsString } from "class-validator"
|
||||
import { Request, Response } from "express"
|
||||
import { EntityManager } from "typeorm"
|
||||
|
||||
import { EntityManager } from "typeorm"
|
||||
import { IsString } from "class-validator"
|
||||
import { SalesChannelLocationService } from "../../../../services"
|
||||
|
||||
/**
|
||||
@@ -80,7 +80,7 @@ export default async (req: Request, res: Response) => {
|
||||
await manager.transaction(async (transactionManager) => {
|
||||
await channelLocationService
|
||||
.withTransaction(transactionManager)
|
||||
.removeLocation(id, validatedBody.location_id)
|
||||
.removeLocation(validatedBody.location_id, id)
|
||||
})
|
||||
|
||||
res.json({
|
||||
|
||||
Reference in New Issue
Block a user