fix(dashboard): Product create price columns race condition (#8943)

This commit is contained in:
Kasper Fabricius Kristensen authored and GitHub committed 2024-09-02 18:56:05 +02:00
1 parent 479e712c17
commit d88e6474e9
3 files changed
+95 -68

No files matched your search

@@ -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.id] = reg.currency_code (acc, reg) => {
return acc acc[reg.id] = reg.currency_code
}, {} as Record<string, string>) return acc
},
{} 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
@@ -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,
regions,
store,
pricePreferences,
}: ProductCreateVariantsFormProps) => { }: ProductCreateVariantsFormProps) => {
const {
regions,
isPending: isRegionsPending,
isError: isRegionError,
error: regionError,
} = useRegions({ limit: 9999 })
const {
store,
isPending: isStorePending,
isError: isStoreError,
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}
@@ -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>
) )
} }