Merged in feat/LOY-55-Filter-Modal (pull request #1509)
feat(LOY-55): Add FilterRewardsModal * feat(LOY-55): Add rewards filtering functionality - Implement dynamic rewards filtering by category and membership level - Create FilterRewardsModal component for filtering rewards - Add useFilteredRewards hook to handle filtering logic - Update rewards schema and constants to support new filtering features - Remove hardcoded page size and replace with constant * fix(LOY-55): reuse existing tier to friend map * refactor(LOY-55): fix checkbox onChange type safety * refactor(LOY-55): Improve rewards filtering type safety and validation * refactor(LOY-55): Update filter modal border color using design token Approved-by: Christian Andolf
This commit is contained in:
79
apps/scandic-web/hooks/rewards/useFilteredRewards.ts
Normal file
79
apps/scandic-web/hooks/rewards/useFilteredRewards.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { useMemo } from "react"
|
||||
|
||||
import { isMembershipLevel } from "@/utils/membershipLevels"
|
||||
import { isRewardCategory } from "@/utils/rewards"
|
||||
|
||||
import type { RewardCategory } from "@/types/components/myPages/rewards"
|
||||
import type { MembershipLevelEnum } from "@/constants/membershipLevels"
|
||||
import type {
|
||||
Reward,
|
||||
RewardWithRedeem,
|
||||
} from "@/server/routers/contentstack/reward/output"
|
||||
|
||||
export function useFilteredRewards(
|
||||
rewards: (Reward | RewardWithRedeem)[],
|
||||
selectedCategories: RewardCategory[] = [],
|
||||
selectedLevels: MembershipLevelEnum[] = []
|
||||
) {
|
||||
const availableCategories = Array.from(
|
||||
new Set(
|
||||
rewards
|
||||
.flatMap((reward) => reward.categories || [])
|
||||
.filter((category) => isRewardCategory(category))
|
||||
)
|
||||
).sort()
|
||||
|
||||
const availableTierLevels = Array.from(
|
||||
new Set(
|
||||
rewards
|
||||
.map((reward) => reward.rewardTierLevel)
|
||||
.filter(
|
||||
(level): level is MembershipLevelEnum =>
|
||||
typeof level === "string" && isMembershipLevel(level)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
const hasFilterableOptions =
|
||||
availableCategories.length > 0 || availableTierLevels.length > 0
|
||||
|
||||
const filteredRewards = useMemo(() => {
|
||||
const hasSelectedCategoryFilter = selectedCategories.length > 0
|
||||
const hasSelectedLevelFilter = selectedLevels.length > 0
|
||||
|
||||
if (!hasSelectedCategoryFilter && !hasSelectedLevelFilter) {
|
||||
return rewards
|
||||
}
|
||||
|
||||
const useOrLogic = hasSelectedCategoryFilter && hasSelectedLevelFilter
|
||||
|
||||
return rewards.filter((reward) => {
|
||||
const matchesCategory =
|
||||
!hasSelectedCategoryFilter ||
|
||||
(reward.categories?.some(
|
||||
(category) =>
|
||||
isRewardCategory(category) && selectedCategories.includes(category)
|
||||
) ??
|
||||
false)
|
||||
|
||||
const matchesLevel =
|
||||
!hasSelectedLevelFilter ||
|
||||
(reward.rewardTierLevel &&
|
||||
isMembershipLevel(reward.rewardTierLevel) &&
|
||||
selectedLevels.includes(reward.rewardTierLevel))
|
||||
|
||||
// Apply OR logic if both filters are active, otherwise AND
|
||||
return useOrLogic
|
||||
? matchesCategory || matchesLevel
|
||||
: matchesCategory && matchesLevel
|
||||
})
|
||||
}, [rewards, selectedCategories, selectedLevels])
|
||||
|
||||
return {
|
||||
filteredRewards,
|
||||
total: filteredRewards.length,
|
||||
availableTierLevels,
|
||||
availableCategories,
|
||||
hasFilterableOptions,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user