fix(dashboard): support more decimals for tx rates (#13407)
* Percentage formatter set maximum digits to 4 * Modify Tax Region Forms to allow 4 digits tax rates * Add changeset * Revert placeholder value to use only 2 decimals * fix(dashboard): support more decimals for tx rates * changeset * bypass scale * refactor * fix removal of deprecated input * cleanup deprecated percentage input * small mistake in onchange * add deprecated percentage input back * import * remove file extension * frane comment --------- Co-authored-by: AmbroziuBaban <ambroziubaban@gmail.com>
This commit is contained in:
1 parent
0000ed6998
commit
9b3831d258
10 files changed
+102
-41
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/dashboard": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(dashboard): support more decimals for tx rates
|
||||||
+67
-37
@@ -1,10 +1,22 @@
|
|||||||
import { Input, Text, clx } from "@medusajs/ui"
|
import { clx, Input, Text } from "@medusajs/ui"
|
||||||
|
import { getNumberOfDecimalPlaces } from "../../../lib/number-helper"
|
||||||
import { ComponentProps, ElementRef, forwardRef } from "react"
|
import { ComponentProps, ElementRef, forwardRef } from "react"
|
||||||
import Primitive from "react-currency-input-field"
|
import Primitive from "react-currency-input-field"
|
||||||
|
|
||||||
/**
|
const MIN_DECIMAL_SCALE = 2
|
||||||
* @deprecated Use `PercentageInput` instead
|
|
||||||
*/
|
function resolveDecimalScale(
|
||||||
|
value: string | readonly string[] | number | undefined | null
|
||||||
|
): number | undefined {
|
||||||
|
if (value == null || Array.isArray(value)) {
|
||||||
|
return MIN_DECIMAL_SCALE
|
||||||
|
}
|
||||||
|
return Math.max(
|
||||||
|
getNumberOfDecimalPlaces(parseFloat(value.toString())),
|
||||||
|
MIN_DECIMAL_SCALE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export const DeprecatedPercentageInput = forwardRef<
|
export const DeprecatedPercentageInput = forwardRef<
|
||||||
ElementRef<typeof Input>,
|
ElementRef<typeof Input>,
|
||||||
Omit<ComponentProps<typeof Input>, "type">
|
Omit<ComponentProps<typeof Input>, "type">
|
||||||
@@ -38,38 +50,56 @@ DeprecatedPercentageInput.displayName = "PercentageInput"
|
|||||||
export const PercentageInput = forwardRef<
|
export const PercentageInput = forwardRef<
|
||||||
ElementRef<"input">,
|
ElementRef<"input">,
|
||||||
ComponentProps<typeof Primitive>
|
ComponentProps<typeof Primitive>
|
||||||
>(({ min = 0, decimalScale = 2, className, ...props }, ref) => {
|
>(
|
||||||
return (
|
(
|
||||||
<div className="relative">
|
{
|
||||||
<Primitive
|
min = 0,
|
||||||
ref={ref as any} // dependency is typed incorrectly
|
max = 100,
|
||||||
min={min}
|
decimalScale,
|
||||||
autoComplete="off"
|
decimalsLimit,
|
||||||
decimalScale={decimalScale}
|
value,
|
||||||
decimalsLimit={decimalScale}
|
className,
|
||||||
{...props}
|
...props
|
||||||
className={clx(
|
},
|
||||||
"caret-ui-fg-base 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 pr-10 text-right outline-none",
|
ref
|
||||||
"placeholder:text-ui-fg-muted text-ui-fg-base",
|
) => {
|
||||||
"hover:bg-ui-bg-field-hover",
|
const resolvedDecimalScale = decimalScale ?? resolveDecimalScale(value)
|
||||||
"focus-visible:shadow-borders-interactive-with-active data-[state=open]:!shadow-borders-interactive-with-active",
|
const resolvedDecimalsLimit = decimalsLimit ?? resolvedDecimalScale
|
||||||
"aria-[invalid=true]:border-ui-border-error aria-[invalid=true]:shadow-borders-error",
|
|
||||||
"invalid::border-ui-border-error invalid:shadow-borders-error",
|
return (
|
||||||
"disabled:!bg-ui-bg-disabled disabled:!text-ui-fg-disabled",
|
<div className="relative">
|
||||||
className
|
<Primitive
|
||||||
)}
|
ref={ref as any} // dependency is typed incorrectly
|
||||||
/>
|
min={min}
|
||||||
<div className="absolute inset-y-0 right-0 z-10 flex w-8 items-center justify-center border-l">
|
max={max}
|
||||||
<Text
|
autoComplete="off"
|
||||||
className="text-ui-fg-muted"
|
decimalScale={resolvedDecimalScale}
|
||||||
size="small"
|
decimalsLimit={resolvedDecimalsLimit}
|
||||||
leading="compact"
|
value={value}
|
||||||
weight="plus"
|
{...props}
|
||||||
>
|
className={clx(
|
||||||
%
|
"caret-ui-fg-base 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 pl-10 text-left outline-none",
|
||||||
</Text>
|
"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",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-y-0 left-0 z-10 flex w-8 items-center justify-center border-r">
|
||||||
|
<Text
|
||||||
|
className="text-ui-fg-muted"
|
||||||
|
size="small"
|
||||||
|
leading="compact"
|
||||||
|
weight="plus"
|
||||||
|
>
|
||||||
|
%
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
)
|
}
|
||||||
})
|
)
|
||||||
PercentageInput.displayName = "PercentageInput"
|
PercentageInput.displayName = "PercentageInput"
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Gets the number of decimal places in a number
|
||||||
|
* @param num - The number for which we are getting the number of decimal places
|
||||||
|
* @returns The number of decimal places
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* getDecimalPlaces(123.456) // 3
|
||||||
|
* getDecimalPlaces(42) // 0
|
||||||
|
* getDecimalPlaces(10.0000) // 0
|
||||||
|
*/
|
||||||
|
export function getNumberOfDecimalPlaces(num: number): number {
|
||||||
|
// Convert to string and check if it contains a decimal point
|
||||||
|
const str = num.toString()
|
||||||
|
if (str.indexOf(".") === -1) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Return the length of the part after the decimal point
|
||||||
|
return str.split(".")[1].length
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
const formatter = new Intl.NumberFormat([], {
|
const formatter = new Intl.NumberFormat([], {
|
||||||
style: "percent",
|
style: "percent",
|
||||||
minimumFractionDigits: 2,
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 4,
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+2
-1
@@ -3,7 +3,7 @@ import { useForm } from "react-hook-form"
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
|
||||||
import { InformationCircleSolid } from "@medusajs/icons"
|
import { InformationCircleSolid } from "@medusajs/icons"
|
||||||
import { Button, Heading, Input, Text, Tooltip, toast } from "@medusajs/ui"
|
import { Button, Heading, Input, Text, toast, Tooltip } from "@medusajs/ui"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { Form } from "../../../../../components/common/form"
|
import { Form } from "../../../../../components/common/form"
|
||||||
import { CountrySelect } from "../../../../../components/inputs/country-select"
|
import { CountrySelect } from "../../../../../components/inputs/country-select"
|
||||||
@@ -221,6 +221,7 @@ export const TaxRegionCreateForm = ({ parentId }: TaxRegionCreateFormProps) => {
|
|||||||
<PercentageInput
|
<PercentageInput
|
||||||
{...field}
|
{...field}
|
||||||
value={value?.value}
|
value={value?.value}
|
||||||
|
decimalsLimit={4}
|
||||||
onValueChange={(value, _name, values) =>
|
onValueChange={(value, _name, values) =>
|
||||||
onChange({
|
onChange({
|
||||||
value: value,
|
value: value,
|
||||||
|
|||||||
+2
-1
@@ -1,7 +1,7 @@
|
|||||||
import { zodResolver } from "@hookform/resolvers/zod"
|
import { zodResolver } from "@hookform/resolvers/zod"
|
||||||
import { InformationCircleSolid } from "@medusajs/icons"
|
import { InformationCircleSolid } from "@medusajs/icons"
|
||||||
import { HttpTypes } from "@medusajs/types"
|
import { HttpTypes } from "@medusajs/types"
|
||||||
import { Button, Heading, Input, Text, Tooltip, toast } from "@medusajs/ui"
|
import { Button, Heading, Input, Text, toast, Tooltip } 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 { z } from "zod"
|
import { z } from "zod"
|
||||||
@@ -189,6 +189,7 @@ export const TaxRegionProvinceCreateForm = ({
|
|||||||
<PercentageInput
|
<PercentageInput
|
||||||
{...field}
|
{...field}
|
||||||
value={value?.value}
|
value={value?.value}
|
||||||
|
decimalsLimit={4}
|
||||||
onValueChange={(value, _name, values) =>
|
onValueChange={(value, _name, values) =>
|
||||||
onChange({
|
onChange({
|
||||||
value: value,
|
value: value,
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
import { zodResolver } from "@hookform/resolvers/zod"
|
import { zodResolver } from "@hookform/resolvers/zod"
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
|
clx,
|
||||||
Divider,
|
Divider,
|
||||||
Heading,
|
Heading,
|
||||||
Hint,
|
Hint,
|
||||||
@@ -8,7 +9,6 @@ import {
|
|||||||
Label,
|
Label,
|
||||||
Select,
|
Select,
|
||||||
Text,
|
Text,
|
||||||
clx,
|
|
||||||
toast,
|
toast,
|
||||||
} from "@medusajs/ui"
|
} from "@medusajs/ui"
|
||||||
import { useFieldArray, useForm, useWatch } from "react-hook-form"
|
import { useFieldArray, useForm, useWatch } from "react-hook-form"
|
||||||
@@ -414,6 +414,7 @@ export const TaxRegionCreateTaxOverrideForm = ({
|
|||||||
<PercentageInput
|
<PercentageInput
|
||||||
{...field}
|
{...field}
|
||||||
placeholder="0.00"
|
placeholder="0.00"
|
||||||
|
decimalsLimit={4}
|
||||||
value={value?.value}
|
value={value?.value}
|
||||||
onValueChange={(value, _name, values) =>
|
onValueChange={(value, _name, values) =>
|
||||||
onChange({
|
onChange({
|
||||||
|
|||||||
+2
-1
@@ -3,6 +3,7 @@ import { MagnifyingGlass } from "@medusajs/icons"
|
|||||||
import { HttpTypes } from "@medusajs/types"
|
import { HttpTypes } from "@medusajs/types"
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
|
clx,
|
||||||
Divider,
|
Divider,
|
||||||
Heading,
|
Heading,
|
||||||
Hint,
|
Hint,
|
||||||
@@ -10,7 +11,6 @@ import {
|
|||||||
Label,
|
Label,
|
||||||
Select,
|
Select,
|
||||||
Text,
|
Text,
|
||||||
clx,
|
|
||||||
toast,
|
toast,
|
||||||
} from "@medusajs/ui"
|
} from "@medusajs/ui"
|
||||||
import { useFieldArray, useForm, useWatch } from "react-hook-form"
|
import { useFieldArray, useForm, useWatch } from "react-hook-form"
|
||||||
@@ -414,6 +414,7 @@ export const TaxRegionTaxOverrideEditForm = ({
|
|||||||
<PercentageInput
|
<PercentageInput
|
||||||
{...field}
|
{...field}
|
||||||
value={value?.value}
|
value={value?.value}
|
||||||
|
decimalsLimit={4}
|
||||||
onValueChange={(value, _name, values) =>
|
onValueChange={(value, _name, values) =>
|
||||||
onChange({
|
onChange({
|
||||||
value: value,
|
value: value,
|
||||||
|
|||||||
+1
@@ -119,6 +119,7 @@ export const TaxRegionTaxRateCreateForm = ({
|
|||||||
<PercentageInput
|
<PercentageInput
|
||||||
{...field}
|
{...field}
|
||||||
value={value?.value}
|
value={value?.value}
|
||||||
|
decimalsLimit={4}
|
||||||
onValueChange={(value, _name, values) =>
|
onValueChange={(value, _name, values) =>
|
||||||
onChange({
|
onChange({
|
||||||
value: value,
|
value: value,
|
||||||
|
|||||||
+1
@@ -117,6 +117,7 @@ export const TaxRegionTaxRateEditForm = ({
|
|||||||
<PercentageInput
|
<PercentageInput
|
||||||
{...field}
|
{...field}
|
||||||
value={value?.value}
|
value={value?.value}
|
||||||
|
decimalsLimit={4}
|
||||||
onValueChange={(value, _name, values) =>
|
onValueChange={(value, _name, values) =>
|
||||||
onChange({
|
onChange({
|
||||||
value: value,
|
value: value,
|
||||||
|
|||||||
Reference in new issue
Block a user