fix(dashboard): Product create price columns race condition (#8943)
This commit is contained in:
1 parent
479e712c17
commit
d88e6474e9
3 files changed
+92
-65
No files matched your search
+21
-11
@@ -1,5 +1,5 @@
|
|||||||
import { zodResolver } from "@hookform/resolvers/zod"
|
import { zodResolver } from "@hookform/resolvers/zod"
|
||||||
import { HttpTypes, SalesChannelDTO } from "@medusajs/types"
|
import { HttpTypes } from "@medusajs/types"
|
||||||
import { Button, ProgressStatus, ProgressTabs, toast } from "@medusajs/ui"
|
import { Button, ProgressStatus, ProgressTabs, toast } from "@medusajs/ui"
|
||||||
import { useEffect, useMemo, useState } from "react"
|
import { useEffect, useMemo, useState } from "react"
|
||||||
import { useForm, useWatch } from "react-hook-form"
|
import { useForm, useWatch } from "react-hook-form"
|
||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
useRouteModal,
|
useRouteModal,
|
||||||
} from "../../../../../components/modals"
|
} from "../../../../../components/modals"
|
||||||
import { useCreateProduct } from "../../../../../hooks/api/products"
|
import { useCreateProduct } from "../../../../../hooks/api/products"
|
||||||
import { useRegions } from "../../../../../hooks/api/regions"
|
|
||||||
import { sdk } from "../../../../../lib/client"
|
import { sdk } from "../../../../../lib/client"
|
||||||
import { isFetchError } from "../../../../../lib/is-fetch-error"
|
import { isFetchError } from "../../../../../lib/is-fetch-error"
|
||||||
import {
|
import {
|
||||||
@@ -34,12 +33,18 @@ type TabState = Record<Tab, ProgressStatus>
|
|||||||
|
|
||||||
const SAVE_DRAFT_BUTTON = "save-draft-button"
|
const SAVE_DRAFT_BUTTON = "save-draft-button"
|
||||||
|
|
||||||
let LAST_VISITED_TAB: Tab | null = null
|
type ProductCreateFormProps = {
|
||||||
|
defaultChannel?: HttpTypes.AdminSalesChannel
|
||||||
type ProductCreateFormProps = { defaultChannel?: SalesChannelDTO }
|
regions: HttpTypes.AdminRegion[]
|
||||||
|
store: HttpTypes.AdminStore
|
||||||
|
pricePreferences: HttpTypes.AdminPricePreference[]
|
||||||
|
}
|
||||||
|
|
||||||
export const ProductCreateForm = ({
|
export const ProductCreateForm = ({
|
||||||
defaultChannel,
|
defaultChannel,
|
||||||
|
regions,
|
||||||
|
store,
|
||||||
|
pricePreferences,
|
||||||
}: ProductCreateFormProps) => {
|
}: ProductCreateFormProps) => {
|
||||||
const [tab, setTab] = useState<Tab>(Tab.DETAILS)
|
const [tab, setTab] = useState<Tab>(Tab.DETAILS)
|
||||||
const [tabState, setTabState] = useState<TabState>({
|
const [tabState, setTabState] = useState<TabState>({
|
||||||
@@ -63,17 +68,19 @@ export const ProductCreateForm = ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const { mutateAsync, isPending } = useCreateProduct()
|
const { mutateAsync, isPending } = useCreateProduct()
|
||||||
const { regions } = useRegions({ limit: 9999 })
|
|
||||||
|
|
||||||
const regionsCurrencyMap = useMemo(() => {
|
const regionsCurrencyMap = useMemo(() => {
|
||||||
if (!regions?.length) {
|
if (!regions?.length) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
return regions.reduce((acc, reg) => {
|
return regions.reduce(
|
||||||
|
(acc, reg) => {
|
||||||
acc[reg.id] = reg.currency_code
|
acc[reg.id] = reg.currency_code
|
||||||
return acc
|
return acc
|
||||||
}, {} as Record<string, string>)
|
},
|
||||||
|
{} as Record<string, string>
|
||||||
|
)
|
||||||
}, [regions])
|
}, [regions])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -197,8 +204,6 @@ export const ProductCreateForm = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
setTabState({ ...currentState })
|
setTabState({ ...currentState })
|
||||||
|
|
||||||
LAST_VISITED_TAB = tab
|
|
||||||
}, [tab])
|
}, [tab])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -284,7 +289,12 @@ export const ProductCreateForm = ({
|
|||||||
className="size-full overflow-y-auto"
|
className="size-full overflow-y-auto"
|
||||||
value={Tab.VARIANTS}
|
value={Tab.VARIANTS}
|
||||||
>
|
>
|
||||||
<ProductCreateVariantsForm form={form} />
|
<ProductCreateVariantsForm
|
||||||
|
form={form}
|
||||||
|
store={store}
|
||||||
|
regions={regions}
|
||||||
|
pricePreferences={pricePreferences}
|
||||||
|
/>
|
||||||
</ProgressTabs.Content>
|
</ProgressTabs.Content>
|
||||||
{showInventoryTab && (
|
{showInventoryTab && (
|
||||||
<ProgressTabs.Content
|
<ProgressTabs.Content
|
||||||
|
|||||||
+6
-45
@@ -9,9 +9,6 @@ import {
|
|||||||
DataGrid,
|
DataGrid,
|
||||||
} from "../../../../../components/data-grid"
|
} from "../../../../../components/data-grid"
|
||||||
import { useRouteModal } from "../../../../../components/modals"
|
import { useRouteModal } from "../../../../../components/modals"
|
||||||
import { usePricePreferences } from "../../../../../hooks/api/price-preferences"
|
|
||||||
import { useRegions } from "../../../../../hooks/api/regions"
|
|
||||||
import { useStore } from "../../../../../hooks/api/store"
|
|
||||||
import {
|
import {
|
||||||
ProductCreateOptionSchema,
|
ProductCreateOptionSchema,
|
||||||
ProductCreateVariantSchema,
|
ProductCreateVariantSchema,
|
||||||
@@ -20,32 +17,17 @@ import { ProductCreateSchemaType } from "../../types"
|
|||||||
|
|
||||||
type ProductCreateVariantsFormProps = {
|
type ProductCreateVariantsFormProps = {
|
||||||
form: UseFormReturn<ProductCreateSchemaType>
|
form: UseFormReturn<ProductCreateSchemaType>
|
||||||
|
regions: HttpTypes.AdminRegion[]
|
||||||
|
store: HttpTypes.AdminStore
|
||||||
|
pricePreferences: HttpTypes.AdminPricePreference[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProductCreateVariantsForm = ({
|
export const ProductCreateVariantsForm = ({
|
||||||
form,
|
form,
|
||||||
}: ProductCreateVariantsFormProps) => {
|
|
||||||
const {
|
|
||||||
regions,
|
regions,
|
||||||
isPending: isRegionsPending,
|
|
||||||
isError: isRegionError,
|
|
||||||
error: regionError,
|
|
||||||
} = useRegions({ limit: 9999 })
|
|
||||||
|
|
||||||
const {
|
|
||||||
store,
|
store,
|
||||||
isPending: isStorePending,
|
pricePreferences,
|
||||||
isError: isStoreError,
|
}: ProductCreateVariantsFormProps) => {
|
||||||
error: storeError,
|
|
||||||
} = useStore()
|
|
||||||
|
|
||||||
const {
|
|
||||||
price_preferences,
|
|
||||||
isPending: isPricePreferencesPending,
|
|
||||||
isError: isPricePreferencesError,
|
|
||||||
error: pricePreferencesError,
|
|
||||||
} = usePricePreferences({})
|
|
||||||
|
|
||||||
const { setCloseOnEscape } = useRouteModal()
|
const { setCloseOnEscape } = useRouteModal()
|
||||||
|
|
||||||
const currencyCodes = useMemo(
|
const currencyCodes = useMemo(
|
||||||
@@ -72,7 +54,7 @@ export const ProductCreateVariantsForm = ({
|
|||||||
options,
|
options,
|
||||||
currencies: currencyCodes,
|
currencies: currencyCodes,
|
||||||
regions,
|
regions,
|
||||||
pricePreferences: price_preferences,
|
pricePreferences,
|
||||||
})
|
})
|
||||||
|
|
||||||
const variantData = useMemo(
|
const variantData = useMemo(
|
||||||
@@ -80,30 +62,9 @@ export const ProductCreateVariantsForm = ({
|
|||||||
[variants]
|
[variants]
|
||||||
)
|
)
|
||||||
|
|
||||||
const isPending =
|
|
||||||
isRegionsPending ||
|
|
||||||
isStorePending ||
|
|
||||||
isPricePreferencesPending ||
|
|
||||||
!store ||
|
|
||||||
!regions ||
|
|
||||||
!price_preferences
|
|
||||||
|
|
||||||
if (isRegionError) {
|
|
||||||
throw regionError
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isStoreError) {
|
|
||||||
throw storeError
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPricePreferencesError) {
|
|
||||||
throw pricePreferencesError
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex size-full flex-col divide-y overflow-hidden">
|
<div className="flex size-full flex-col divide-y overflow-hidden">
|
||||||
<DataGrid
|
<DataGrid
|
||||||
isLoading={isPending}
|
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={variantData}
|
data={variantData}
|
||||||
state={form}
|
state={form}
|
||||||
|
|||||||
+65
-9
@@ -1,25 +1,81 @@
|
|||||||
import { RouteFocusModal } from "../../../components/modals"
|
import { RouteFocusModal } from "../../../components/modals"
|
||||||
|
import { useRegions } from "../../../hooks/api"
|
||||||
|
import { usePricePreferences } from "../../../hooks/api/price-preferences"
|
||||||
import { useSalesChannel } from "../../../hooks/api/sales-channels"
|
import { useSalesChannel } from "../../../hooks/api/sales-channels"
|
||||||
import { useStore } from "../../../hooks/api/store"
|
import { useStore } from "../../../hooks/api/store"
|
||||||
import { ProductCreateForm } from "./components/product-create-form/product-create-form"
|
import { ProductCreateForm } from "./components/product-create-form/product-create-form"
|
||||||
|
|
||||||
export const ProductCreate = () => {
|
export const ProductCreate = () => {
|
||||||
const { store } = useStore({
|
const {
|
||||||
|
store,
|
||||||
|
isPending: isStorePending,
|
||||||
|
isError: isStoreError,
|
||||||
|
error: storeError,
|
||||||
|
} = useStore({
|
||||||
fields: "default_sales_channel",
|
fields: "default_sales_channel",
|
||||||
})
|
})
|
||||||
|
|
||||||
const { sales_channel, isPending } = useSalesChannel(
|
const {
|
||||||
store?.default_sales_channel_id,
|
sales_channel,
|
||||||
{
|
isPending: isSalesChannelPending,
|
||||||
enabled: !!store,
|
isError: isSalesChannelError,
|
||||||
}
|
error: salesChannelError,
|
||||||
)
|
} = useSalesChannel(store?.default_sales_channel_id!, {
|
||||||
|
enabled: !!store?.default_sales_channel_id,
|
||||||
|
})
|
||||||
|
|
||||||
const canDisplayForm = store && !isPending
|
const {
|
||||||
|
regions,
|
||||||
|
isPending: isRegionsPending,
|
||||||
|
isError: isRegionsError,
|
||||||
|
error: regionsError,
|
||||||
|
} = useRegions({ limit: 9999 })
|
||||||
|
|
||||||
|
const {
|
||||||
|
price_preferences,
|
||||||
|
isPending: isPricePreferencesPending,
|
||||||
|
isError: isPricePreferencesError,
|
||||||
|
error: pricePreferencesError,
|
||||||
|
} = usePricePreferences({
|
||||||
|
limit: 9999,
|
||||||
|
})
|
||||||
|
|
||||||
|
const ready =
|
||||||
|
!!store &&
|
||||||
|
!isStorePending &&
|
||||||
|
!!regions &&
|
||||||
|
!isRegionsPending &&
|
||||||
|
!!sales_channel &&
|
||||||
|
!isSalesChannelPending &&
|
||||||
|
!!price_preferences &&
|
||||||
|
!isPricePreferencesPending
|
||||||
|
|
||||||
|
if (isStoreError) {
|
||||||
|
throw storeError
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRegionsError) {
|
||||||
|
throw regionsError
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSalesChannelError) {
|
||||||
|
throw salesChannelError
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPricePreferencesError) {
|
||||||
|
throw pricePreferencesError
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RouteFocusModal>
|
<RouteFocusModal>
|
||||||
{canDisplayForm && <ProductCreateForm defaultChannel={sales_channel} />}
|
{ready && (
|
||||||
|
<ProductCreateForm
|
||||||
|
defaultChannel={sales_channel}
|
||||||
|
store={store}
|
||||||
|
pricePreferences={price_preferences}
|
||||||
|
regions={regions}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</RouteFocusModal>
|
</RouteFocusModal>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user