fix(dashboard): replace native select Element in CountrySelect & ProvinceSelect with Select(Medusa UI). (#13521)
* fix: replace CountrySelect fallback with Medusa Select * Country Select Component Fix to use Medusa UI Select Component * added Change set * using the props supported by the Select * value should be lowercased if passed from the pareant component * fix province Select with medusa UI select and added change set * bug fix the province with providing --------- Co-authored-by: Aryan Patel <21cs038@charusat.edu.in> Co-authored-by: William Bouchard <46496014+willbouch@users.noreply.github.com>
This commit is contained in:
4 files changed
+75
-116
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/dashboard": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(dashboard):replace native select Element in CountrySelect & ProvinceSelect with Select(Medusa UI).
|
||||||
@@ -4,75 +4,50 @@ import {
|
|||||||
useImperativeHandle,
|
useImperativeHandle,
|
||||||
useRef,
|
useRef,
|
||||||
} from "react"
|
} from "react"
|
||||||
|
|
||||||
import { TrianglesMini } from "@medusajs/icons"
|
|
||||||
import { clx } from "@medusajs/ui"
|
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { countries } from "../../../lib/data/countries"
|
import { countries } from "../../../lib/data/countries"
|
||||||
|
import { Select } from "@medusajs/ui"
|
||||||
|
|
||||||
export const CountrySelect = forwardRef<
|
export const CountrySelect = forwardRef<
|
||||||
HTMLSelectElement,
|
HTMLButtonElement,
|
||||||
ComponentPropsWithoutRef<"select"> & {
|
ComponentPropsWithoutRef<typeof Select> & {
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
value?: string
|
|
||||||
defaultValue?: string
|
defaultValue?: string
|
||||||
|
onChange?: (value: string) => void
|
||||||
}
|
}
|
||||||
>(
|
>(({ disabled, placeholder, defaultValue, onChange, ...field }, ref) => {
|
||||||
(
|
|
||||||
{ className, disabled, placeholder, value, defaultValue, ...props },
|
|
||||||
ref
|
|
||||||
) => {
|
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const innerRef = useRef<HTMLSelectElement>(null)
|
const innerRef = useRef<HTMLButtonElement>(null)
|
||||||
|
|
||||||
useImperativeHandle(ref, () => innerRef.current as HTMLSelectElement)
|
useImperativeHandle(ref, () => innerRef.current as HTMLButtonElement)
|
||||||
|
|
||||||
const isPlaceholder = innerRef.current?.value === ""
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<TrianglesMini
|
<Select
|
||||||
className={clx(
|
{...field}
|
||||||
"text-ui-fg-muted transition-fg pointer-events-none absolute end-2 top-1/2 -translate-y-1/2",
|
value={field.value ? field.value?.toLowerCase() : undefined}
|
||||||
{
|
onValueChange={onChange}
|
||||||
"text-ui-fg-disabled": disabled,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<select
|
|
||||||
value={value !== undefined ? value.toLowerCase() : undefined}
|
|
||||||
defaultValue={defaultValue ? defaultValue.toLowerCase() : undefined}
|
defaultValue={defaultValue ? defaultValue.toLowerCase() : undefined}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
className={clx(
|
|
||||||
"bg-ui-bg-field shadow-buttons-neutral transition-fg txt-compact-small flex w-full select-none appearance-none items-center justify-between rounded-md px-2 py-1.5 outline-none",
|
|
||||||
"placeholder:text-ui-fg-muted text-ui-fg-base",
|
|
||||||
"hover:bg-ui-bg-field-hover",
|
|
||||||
"focus-visible:shadow-borders-interactive-with-active data-[state=open]:!shadow-borders-interactive-with-active",
|
|
||||||
"aria-[invalid=true]:border-ui-border-error aria-[invalid=true]:shadow-borders-error",
|
|
||||||
"invalid::border-ui-border-error invalid:shadow-borders-error",
|
|
||||||
"disabled:!bg-ui-bg-disabled disabled:!text-ui-fg-disabled",
|
|
||||||
{
|
|
||||||
"text-ui-fg-muted": isPlaceholder,
|
|
||||||
},
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
ref={innerRef}
|
|
||||||
>
|
>
|
||||||
{/* Add an empty option so the first option is preselected */}
|
<Select.Trigger ref={innerRef} className="w-full">
|
||||||
<option value="" disabled className="text-ui-fg-muted">
|
<Select.Value
|
||||||
{placeholder || t("fields.selectCountry")}
|
placeholder={placeholder || t("fields.selectCountry")}
|
||||||
</option>
|
/>
|
||||||
{countries.map((country) => {
|
</Select.Trigger>
|
||||||
return (
|
<Select.Content>
|
||||||
<option key={country.iso_2} value={country.iso_2.toLowerCase()}>
|
{countries.map((country) => (
|
||||||
|
<Select.Item
|
||||||
|
key={country.iso_2}
|
||||||
|
value={country.iso_2.toLowerCase()}
|
||||||
|
>
|
||||||
{country.display_name}
|
{country.display_name}
|
||||||
</option>
|
</Select.Item>
|
||||||
)
|
))}
|
||||||
})}
|
</Select.Content>
|
||||||
</select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
)
|
|
||||||
CountrySelect.displayName = "CountrySelect"
|
CountrySelect.displayName = "CountrySelect"
|
||||||
+41
-61
@@ -4,47 +4,36 @@ import {
|
|||||||
useImperativeHandle,
|
useImperativeHandle,
|
||||||
useRef,
|
useRef,
|
||||||
} from "react"
|
} from "react"
|
||||||
|
import { Select } from "@medusajs/ui"
|
||||||
import { TrianglesMini } from "@medusajs/icons"
|
|
||||||
import { clx } from "@medusajs/ui"
|
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { getCountryProvinceObjectByIso2 } from "../../../lib/data/country-states"
|
import { getCountryProvinceObjectByIso2 } from "../../../lib/data/country-states"
|
||||||
|
|
||||||
interface ProvinceSelectProps extends ComponentPropsWithoutRef<"select"> {
|
|
||||||
/**
|
|
||||||
* ISO 3166-1 alpha-2 country code
|
|
||||||
*/
|
|
||||||
country_code: string
|
|
||||||
/**
|
|
||||||
* Whether to use the ISO 3166-1 alpha-2 code or the name of the province as the value
|
|
||||||
*
|
|
||||||
* @default "iso_2"
|
|
||||||
*/
|
|
||||||
valueAs?: "iso_2" | "name"
|
|
||||||
placeholder?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ProvinceSelect = forwardRef<
|
export const ProvinceSelect = forwardRef<
|
||||||
HTMLSelectElement,
|
HTMLButtonElement,
|
||||||
ProvinceSelectProps
|
ComponentPropsWithoutRef<typeof Select> & {
|
||||||
|
placeholder?: string
|
||||||
|
defaultValue?: string
|
||||||
|
country_code: string
|
||||||
|
valueAs?: "iso_2" | "name"
|
||||||
|
onChange?: (value: string) => void
|
||||||
|
}
|
||||||
>(
|
>(
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
className,
|
|
||||||
disabled,
|
disabled,
|
||||||
placeholder,
|
placeholder,
|
||||||
|
defaultValue,
|
||||||
country_code,
|
country_code,
|
||||||
valueAs = "iso_2",
|
valueAs = "iso_2",
|
||||||
...props
|
onChange,
|
||||||
|
...field
|
||||||
},
|
},
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const innerRef = useRef<HTMLSelectElement>(null)
|
const innerRef = useRef<HTMLButtonElement>(null)
|
||||||
|
|
||||||
useImperativeHandle(ref, () => innerRef.current as HTMLSelectElement)
|
useImperativeHandle(ref, () => innerRef.current as HTMLButtonElement)
|
||||||
|
|
||||||
const isPlaceholder = innerRef.current?.value === ""
|
|
||||||
|
|
||||||
const provinceObject = getCountryProvinceObjectByIso2(country_code)
|
const provinceObject = getCountryProvinceObjectByIso2(country_code)
|
||||||
|
|
||||||
@@ -55,9 +44,12 @@ export const ProvinceSelect = forwardRef<
|
|||||||
const options = Object.entries(provinceObject?.options ?? {}).map(
|
const options = Object.entries(provinceObject?.options ?? {}).map(
|
||||||
([iso2, name]) => {
|
([iso2, name]) => {
|
||||||
return (
|
return (
|
||||||
<option key={iso2} value={valueAs === "iso_2" ? iso2 : name}>
|
<Select.Item
|
||||||
|
key={iso2}
|
||||||
|
value={valueAs === "iso_2" ? iso2.toLowerCase() : name}
|
||||||
|
>
|
||||||
{name}
|
{name}
|
||||||
</option>
|
</Select.Item>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -66,46 +58,34 @@ export const ProvinceSelect = forwardRef<
|
|||||||
? t(`taxRegions.fields.sublevels.placeholders.${provinceObject.type}`)
|
? t(`taxRegions.fields.sublevels.placeholders.${provinceObject.type}`)
|
||||||
: ""
|
: ""
|
||||||
|
|
||||||
const placeholderOption = provinceObject ? (
|
|
||||||
<option value="" disabled className="text-ui-fg-muted">
|
|
||||||
{placeholder || placeholderText}
|
|
||||||
</option>
|
|
||||||
) : null
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<TrianglesMini
|
<Select
|
||||||
className={clx(
|
{...field}
|
||||||
"text-ui-fg-muted transition-fg pointer-events-none absolute end-2 top-1/2 -translate-y-1/2",
|
value={
|
||||||
{
|
field.value
|
||||||
"text-ui-fg-disabled": disabled,
|
? valueAs === "iso_2"
|
||||||
|
? field.value.toLowerCase()
|
||||||
|
: field.value
|
||||||
|
: undefined
|
||||||
}
|
}
|
||||||
)}
|
defaultValue={
|
||||||
/>
|
defaultValue
|
||||||
<select
|
? valueAs === "iso_2"
|
||||||
|
? defaultValue.toLowerCase()
|
||||||
|
: defaultValue
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onValueChange={onChange}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
className={clx(
|
|
||||||
"bg-ui-bg-field shadow-buttons-neutral transition-fg txt-compact-small flex w-full select-none appearance-none items-center justify-between rounded-md px-2 py-1.5 outline-none",
|
|
||||||
"placeholder:text-ui-fg-muted text-ui-fg-base",
|
|
||||||
"hover:bg-ui-bg-field-hover",
|
|
||||||
"focus-visible:shadow-borders-interactive-with-active data-[state=open]:!shadow-borders-interactive-with-active",
|
|
||||||
"aria-[invalid=true]:border-ui-border-error aria-[invalid=true]:shadow-borders-error",
|
|
||||||
"invalid::border-ui-border-error invalid:shadow-borders-error",
|
|
||||||
"disabled:!bg-ui-bg-disabled disabled:!text-ui-fg-disabled",
|
|
||||||
{
|
|
||||||
"text-ui-fg-muted": isPlaceholder,
|
|
||||||
},
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
ref={innerRef}
|
|
||||||
>
|
>
|
||||||
{/* Add an empty option so the first option is preselected */}
|
<Select.Trigger ref={innerRef} className="w-full">
|
||||||
{placeholderOption}
|
<Select.Value placeholder={placeholder || placeholderText} />
|
||||||
{options}
|
</Select.Trigger>
|
||||||
</select>
|
<Select.Content>{options}</Select.Content>
|
||||||
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
ProvinceSelect.displayName = "CountrySelect"
|
ProvinceSelect.displayName = "ProvinceSelect"
|
||||||
+1
-2
@@ -4,12 +4,11 @@ import { Button, Input, toast } from "@medusajs/ui"
|
|||||||
import { useForm } from "react-hook-form"
|
import { useForm } from "react-hook-form"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import * as zod from "zod"
|
import * as zod from "zod"
|
||||||
|
|
||||||
import { Form } from "../../../../../components/common/form"
|
import { Form } from "../../../../../components/common/form"
|
||||||
import { CountrySelect } from "../../../../../components/inputs/country-select"
|
|
||||||
import { RouteDrawer, useRouteModal } from "../../../../../components/modals"
|
import { RouteDrawer, useRouteModal } from "../../../../../components/modals"
|
||||||
import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
|
import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
|
||||||
import { useUpdateStockLocation } from "../../../../../hooks/api/stock-locations"
|
import { useUpdateStockLocation } from "../../../../../hooks/api/stock-locations"
|
||||||
|
import { CountrySelect } from "../../../../../components/inputs/country-select/country-select"
|
||||||
|
|
||||||
type EditLocationFormProps = {
|
type EditLocationFormProps = {
|
||||||
location: HttpTypes.AdminStockLocation
|
location: HttpTypes.AdminStockLocation
|
||||||
|
|||||||
Reference in new issue
Block a user