fix(admin-ui): Make regions in tax setting scrollable (#5530)
* fix overflow * intersection observer and changeset
This commit is contained in:
committed by
GitHub
parent
3a344964e0
commit
8e48be58ef
5
.changeset/plenty-coins-smell.md
Normal file
5
.changeset/plenty-coins-smell.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@medusajs/admin-ui": patch
|
||||
---
|
||||
|
||||
fix(admin-ui): Fixes an issue where regions were not scrollable in tax settings view, also adds a IntersectionObserver to ensure that we load all regions as the user scrolls. The current implementation was capped at loading 20 regions.
|
||||
@@ -1,23 +1,76 @@
|
||||
import { Region } from "@medusajs/medusa"
|
||||
import { useAdminRegions } from "medusa-react"
|
||||
import { useCallback, useEffect, useState } from "react"
|
||||
import { useNavigate, useParams } from "react-router-dom"
|
||||
import { useCallback, useEffect, useRef, useState } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { useNavigate, useParams } from "react-router-dom"
|
||||
import BackButton from "../../../components/atoms/back-button"
|
||||
import Spinner from "../../../components/atoms/spinner"
|
||||
import GearIcon from "../../../components/fundamentals/icons/gear-icon"
|
||||
import BodyCard from "../../../components/organisms/body-card"
|
||||
import RadioGroup from "../../../components/organisms/radio-group"
|
||||
import TwoSplitPane from "../../../components/templates/two-split-pane"
|
||||
import TaxDetails from "./details"
|
||||
|
||||
const LIMIT = 20
|
||||
|
||||
const Taxes = () => {
|
||||
const params = useParams()
|
||||
const regId: string | undefined = params["*"]
|
||||
|
||||
const [offset, setOffset] = useState(0)
|
||||
const observerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const navigate = useNavigate()
|
||||
const { t } = useTranslation()
|
||||
|
||||
const { regions, isLoading } = useAdminRegions()
|
||||
const [regionOpts, setRegionOpts] = useState<Region[]>([])
|
||||
|
||||
const { regions, count, isLoading } = useAdminRegions({
|
||||
offset,
|
||||
limit: LIMIT,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (regions && !isLoading) {
|
||||
setRegionOpts((prev) => {
|
||||
const exisitngIds = prev.map((r) => r.id)
|
||||
const newOpts = regions.filter((r) => !exisitngIds.includes(r.id))
|
||||
|
||||
return [...prev, ...newOpts]
|
||||
})
|
||||
}
|
||||
}, [regions, isLoading])
|
||||
|
||||
useEffect(() => {
|
||||
const current = observerRef.current
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
// If the ref is in view and there's more data to fetch
|
||||
if (
|
||||
entries[0].isIntersecting &&
|
||||
regionOpts &&
|
||||
regionOpts.length < (count || 0)
|
||||
) {
|
||||
setOffset(regionOpts.length)
|
||||
}
|
||||
},
|
||||
{
|
||||
root: null, // relative to the viewport
|
||||
threshold: 1.0, // trigger when 100% of the ref is visible
|
||||
}
|
||||
)
|
||||
|
||||
if (current) {
|
||||
observer.observe(current)
|
||||
}
|
||||
|
||||
// Clean up the observer on component unmount
|
||||
return () => {
|
||||
if (current) {
|
||||
observer.unobserve(current)
|
||||
}
|
||||
}
|
||||
}, [count, regionOpts])
|
||||
|
||||
const [selectedRegion, setSelectedRegion] = useState<string | undefined>(
|
||||
regId
|
||||
@@ -71,35 +124,40 @@ const Taxes = () => {
|
||||
onClick: () => navigate("/a/settings/regions"),
|
||||
},
|
||||
]}
|
||||
className="no-scrollbar overflow-y-auto"
|
||||
>
|
||||
{isLoading || !regions ? (
|
||||
<div className="flex h-full flex-grow items-center justify-center">
|
||||
<Spinner size="large" variant="secondary" />
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<RadioGroup.Root
|
||||
value={selectedRegion}
|
||||
onValueChange={handleChange}
|
||||
>
|
||||
{regions.map((r) => {
|
||||
{regionOpts.map((r, index) => {
|
||||
return (
|
||||
<RadioGroup.Item
|
||||
label={r.name}
|
||||
description={
|
||||
r.countries.length
|
||||
? `${r.countries
|
||||
.map((c) => c.display_name)
|
||||
.join(", ")}`
|
||||
<div
|
||||
key={r.id}
|
||||
ref={
|
||||
index === regionOpts.length - 1
|
||||
? observerRef
|
||||
: undefined
|
||||
}
|
||||
value={r.id}
|
||||
key={r.id}
|
||||
id={r.id}
|
||||
/>
|
||||
>
|
||||
<RadioGroup.Item
|
||||
label={r.name}
|
||||
description={
|
||||
r.countries.length
|
||||
? `${r.countries
|
||||
.map((c) => c.display_name)
|
||||
.join(", ")}`
|
||||
: undefined
|
||||
}
|
||||
value={r.id}
|
||||
key={r.id}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</RadioGroup.Root>
|
||||
)}
|
||||
</div>
|
||||
</BodyCard>
|
||||
<TaxDetails id={selectedRegion} />
|
||||
</TwoSplitPane>
|
||||
|
||||
Reference in New Issue
Block a user