Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion src/components/ProductTable/Filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,37 @@ interface FilterProps {
onChange: (updatedFilter: FilterOption) => void
}

const arePropsEqual = (prevProps: FilterProps, nextProps: FilterProps) => {
if (prevProps.filterIndex !== nextProps.filterIndex) return false
if (prevProps.filter.title !== nextProps.filter.title) return false
if (prevProps.filter.showFilterOption !== nextProps.filter.showFilterOption)
return false

const prevItems = prevProps.filter.items
const nextItems = nextProps.filter.items

if (prevItems.length !== nextItems.length) return false

for (let i = 0; i < prevItems.length; i++) {
const prevItem = prevItems[i]
const nextItem = nextItems[i]

if (prevItem.filterKey !== nextItem.filterKey) return false
if (prevItem.inputState !== nextItem.inputState) return false

if (prevItem.options.length !== nextItem.options.length) return false

for (let j = 0; j < prevItem.options.length; j++) {
if (prevItem.options[j].filterKey !== nextItem.options[j].filterKey)
return false
if (prevItem.options[j].inputState !== nextItem.options[j].inputState)
return false
}
}

return true
}

const Filter = ({ filter, filterIndex, onChange }: FilterProps) => {
const handleChange = (
_: number,
Expand Down Expand Up @@ -110,4 +141,4 @@ const Filter = ({ filter, filterIndex, onChange }: FilterProps) => {
)
}

export default memo(Filter)
export default memo(Filter, arePropsEqual)
142 changes: 69 additions & 73 deletions src/components/ProductTable/MobileFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,8 @@ import { FilterOption, TPresetFilters } from "@/lib/types"

import Filters from "@/components/ProductTable/Filters"
import PresetFilters from "@/components/ProductTable/PresetFilters"
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer"
import { PersistentPanel } from "@/components/ui/persistent-panel"
import { Sheet, SheetTrigger } from "@/components/ui/sheet"

import { trackCustomEvent } from "@/lib/utils/matomo"

Expand Down Expand Up @@ -49,21 +41,23 @@ const MobileFilters = ({
}: MobileFiltersProps) => {
const { t } = useTranslation("table")

const handleOpenChange = (open: boolean) => {
setMobileFiltersOpen(open)
trackCustomEvent({
eventCategory: "MobileFilterToggle",
eventAction: "Tap MobileFilterToggle",
eventName: `show mobile filters ${open}`,
})
}

const handleClose = () => {
handleOpenChange(false)
}

return (
<div className="border-b border-b-background-highlight">
<Drawer
direction="left"
open={mobileFiltersOpen}
onOpenChange={(open) => {
setMobileFiltersOpen(open)
trackCustomEvent({
eventCategory: "MobileFilterToggle",
eventAction: "Tap MobileFilterToggle",
eventName: `show mobile filters ${open}`,
})
}}
>
<DrawerTrigger className="px-4" asChild>
<Sheet open={mobileFiltersOpen} onOpenChange={handleOpenChange}>
<SheetTrigger className="px-4" asChild>
<Button
variant="outline"
className="gap-4 border-0 ps-4"
Expand All @@ -77,58 +71,60 @@ const MobileFilters = ({
<ListFilter className="-mb-0.5 size-6 stroke-1" />
</div>
</Button>
</DrawerTrigger>
<DrawerContent className="flex h-full flex-col p-2">
<div className="sticky top-0 flex items-center justify-end p-2">
<DrawerClose asChild>
<Button variant="ghost">
<X className="text-2xl" />
</SheetTrigger>
</Sheet>

{/* Persistent content that stays mounted after first render */}
<PersistentPanel
open={mobileFiltersOpen}
side="left"
className="flex h-full flex-col p-2"
onOpenChange={handleOpenChange}
>
<div className="sticky top-0 flex items-center justify-end p-2">
<Button variant="ghost" onClick={handleClose}>
<X className="text-2xl" />
</Button>
</div>
<div className="sr-only">
<h2 className="text-foreground text-lg font-normal">
{t("table-filters")}
</h2>
<p className="text-muted-foreground text-sm">
{`${activeFiltersCount} ${t("table-active")}`}
</p>
</div>
<div className="flex-1 overflow-y-auto">
<PresetFilters
presets={presets}
filters={filters}
presetFiltersCounts={presetFiltersCounts}
setFilters={setFilters}
showMobileSidebar={true}
/>
<Filters
filters={filters}
setFilters={setFilters}
resetFilters={resetFilters}
activeFiltersCount={activeFiltersCount}
/>
</div>
<div className="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2">
<div className="grid w-full grid-cols-2 items-center sm:w-auto">
<div>
<Button variant="ghost" className="gap-1" onClick={resetFilters}>
<RotateCcw />
{t("table-reset-filters")}
</Button>
</DrawerClose>
</div>
<DrawerHeader className="sr-only">
<DrawerTitle>{t("table-filters")}</DrawerTitle>
<DrawerDescription>
{`${activeFiltersCount} ${t("table-active")}`}
</DrawerDescription>
</DrawerHeader>
<div className="flex-1 overflow-y-auto">
<PresetFilters
presets={presets}
filters={filters}
presetFiltersCounts={presetFiltersCounts}
setFilters={setFilters}
showMobileSidebar={true}
/>
<Filters
filters={filters}
setFilters={setFilters}
resetFilters={resetFilters}
activeFiltersCount={activeFiltersCount}
/>
</div>
<DrawerFooter>
<div className="grid grid-cols-2 items-center">
<div>
<Button
variant="ghost"
className="gap-1"
onClick={resetFilters}
>
<RotateCcw />
{t("table-reset-filters")}
</Button>
</div>
<DrawerClose className="text-center" asChild>
<Button
className="w-full"
data-testid="mobile-filters-submit-button"
>{`${mobileFiltersLabel} (${dataCount})`}</Button>
</DrawerClose>
</div>
</DrawerFooter>
</DrawerContent>
</Drawer>
<Button
className="w-full"
onClick={handleClose}
data-testid="mobile-filters-submit-button"
>{`${mobileFiltersLabel} (${dataCount})`}</Button>
</div>
</div>
</PersistentPanel>
</div>
)
}
Expand Down
38 changes: 23 additions & 15 deletions src/components/ProductTable/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { useCallback, useEffect, useMemo, useState } from "react"
import {
startTransition,
useCallback,
useDeferredValue,
useEffect,
useMemo,
useState,
} from "react"
import { useSearchParams } from "next/navigation"

import type { FilterOption, TPresetFilters } from "@/lib/types"
Expand Down Expand Up @@ -77,23 +84,27 @@ const ProductTable = <T extends { id: string }>({

const updateFilters = useCallback(
(filters: FilterOption | FilterOption[]) => {
setFilters((prevFilters) => {
return prevFilters.map((prevFilter) => {
const filter = Array.isArray(filters)
? filters.find((f) => f.title === prevFilter.title)
: filters.title === prevFilter.title
? filters
: prevFilter
if (!filter) return prevFilter
return filter
startTransition(() => {
setFilters((prevFilters) => {
return prevFilters.map((prevFilter) => {
const filter = Array.isArray(filters)
? filters.find((f) => f.title === prevFilter.title)
: filters.title === prevFilter.title
? filters
: prevFilter
if (!filter) return prevFilter
return filter
})
})
})
},
[]
)

const resetFilters = useCallback(() => {
setFilters(initialFilters)
startTransition(() => {
setFilters(initialFilters)
})
onResetFilters?.()
}, [initialFilters, onResetFilters])

Expand All @@ -114,10 +125,7 @@ const ProductTable = <T extends { id: string }>({
})
}, [filteredData, presetFilters])

const activeFiltersCount = useMemo(
() => getActiveFiltersCount(filters),
[filters]
)
const activeFiltersCount = useDeferredValue(getActiveFiltersCount(filters))

return (
<div>
Expand Down
Loading