fix(admin-ui): Make regions in tax setting scrollable (#5530)

* fix overflow

* intersection observer and changeset
This commit is contained in:
Kasper Fabricius Kristensen
2023-11-02 13:03:45 +01:00
committed by GitHub
parent 3a344964e0
commit 8e48be58ef
2 changed files with 85 additions and 22 deletions

View 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.

View File

@@ -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>