refactor(LOY-62): implement code review feedback

This commit is contained in:
Chuma McPhoy
2025-01-13 13:45:13 +01:00
parent e0d8315565
commit da31539610
10 changed files with 61 additions and 143 deletions

View File

@@ -1,98 +0,0 @@
"use client"
import { trpc } from "@/lib/trpc/client"
import { Reward } from "@/server/routers/contentstack/reward/output"
import Image from "@/components/Image"
import LoadingSpinner from "@/components/LoadingSpinner"
import Grids from "@/components/TempDesignSystem/Grids"
import ShowMoreButton from "@/components/TempDesignSystem/ShowMoreButton"
import Title from "@/components/TempDesignSystem/Text/Title"
import useLang from "@/hooks/useLang"
import ScriptedRewardText from "../ScriptedRewardText"
import Redeem from "./Redeem"
import styles from "./current.module.css"
import type { CurrentRewardsClientProps } from "@/types/components/myPages/myPage/accountPage"
export default function ClientCurrentRewards({
initialCurrentRewards,
showRedeem,
}: CurrentRewardsClientProps) {
const lang = useLang()
const { data, isFetching, fetchNextPage, hasNextPage, isLoading } =
trpc.contentstack.rewards.current.useInfiniteQuery(
{
limit: 3,
lang,
},
{
getNextPageParam: (lastPage) => lastPage?.nextCursor,
initialData: {
pageParams: [undefined, 1],
pages: [initialCurrentRewards],
},
}
)
function loadMoreData() {
if (hasNextPage) {
fetchNextPage()
}
}
const filteredRewards = data?.pages.filter((page) => page?.rewards) ?? []
const rewards = filteredRewards
.flatMap((page) => page?.rewards)
.filter((reward): reward is Reward => !!reward)
if (isLoading) {
return <LoadingSpinner />
}
if (!rewards.length) {
return null
}
return (
<div>
<Grids.Stackable>
{rewards.map((reward, idx) => (
<article className={styles.card} key={`${reward.reward_id}-${idx}`}>
<div className={styles.content}>
<Image
src="/_static/img/loyalty-award.png"
width={113}
height={125}
alt={reward.label || ""}
/>
<ScriptedRewardText
rewardType={reward.rewardType}
rewardTierLevel={reward.rewardTierLevel}
/>
<Title
as="h4"
level="h3"
textAlign="center"
textTransform="regular"
>
{reward.label}
</Title>
</div>
{showRedeem && (
<div className={styles.btnContainer}>
<Redeem reward={reward} />
</div>
)}
</article>
))}
</Grids.Stackable>
{hasNextPage &&
(isFetching ? (
<LoadingSpinner />
) : (
<ShowMoreButton loadMoreData={loadMoreData} />
))}
</div>
)
}

View File

@@ -3,6 +3,7 @@
import { useRef, useState } from "react"
import { RewardIcon } from "@/components/Blocks/DynamicContent/Rewards/RewardIcon"
import ScriptedRewardText from "@/components/Blocks/DynamicContent/Rewards/ScriptedRewardText"
import Pagination from "@/components/MyPages/Pagination"
import Grids from "@/components/TempDesignSystem/Grids"
import Title from "@/components/TempDesignSystem/Text/Title"
@@ -45,6 +46,10 @@ export default function ClientCurrentRewards({
<article className={styles.card} key={`${reward.reward_id}-${idx}`}>
<div className={styles.content}>
<RewardIcon rewardId={reward.reward_id} />
<ScriptedRewardText
rewardType={reward.rewardType}
rewardTierLevel={reward.rewardTierLevel}
/>
<Title
as="h4"
level="h3"

View File

@@ -1,23 +1,13 @@
import { useIntl } from "react-intl"
import {
isMembershipLevel,
MembershipLevelEnum,
} from "@/constants/membershipLevels"
import { TIER_TO_FRIEND_MAP } from "@/constants/membershipLevels"
import BiroScript from "@/components/TempDesignSystem/Text/BiroScript"
import { isMembershipLevel } from "@/utils/membershipLevels"
import { isCouponRewardType } from "@/utils/rewards"
import type { ScriptedRewardTextProps } from "@/types/components/myPages/myPage/accountPage"
const TIER_TO_FRIEND_MAP: Record<MembershipLevelEnum, string> = {
[MembershipLevelEnum.L1]: "New Friend",
[MembershipLevelEnum.L2]: "Good Friend",
[MembershipLevelEnum.L3]: "Close Friend",
[MembershipLevelEnum.L4]: "Dear Friend",
[MembershipLevelEnum.L5]: "Loyal Friend",
[MembershipLevelEnum.L6]: "True Friend",
[MembershipLevelEnum.L7]: "Best Friend",
}
import type { CouponRewardType } from "@/types/components/myPages/rewards"
export default function ScriptedRewardText({
rewardType,
@@ -25,31 +15,21 @@ export default function ScriptedRewardText({
}: ScriptedRewardTextProps) {
const intl = useIntl()
let label: string | null = null
switch (rewardType) {
case "Tier":
if (rewardTierLevel && isMembershipLevel(rewardTierLevel)) {
label = TIER_TO_FRIEND_MAP[rewardTierLevel]
}
break
case "Campaign":
label = intl.formatMessage({ id: "Campaign" })
break
case "Surprise":
label = intl.formatMessage({ id: "Surprise!" })
break
case "Member-voucher":
label = intl.formatMessage({ id: "Voucher" })
break
default:
label = null
const couponLabelMap: Record<CouponRewardType, string> = {
Campaign: intl.formatMessage({ id: "Campaign" }),
Surprise: intl.formatMessage({ id: "Surprise!" }),
"Member-voucher": intl.formatMessage({ id: "Voucher" }),
}
const label =
rewardTierLevel && isMembershipLevel(rewardTierLevel)
? TIER_TO_FRIEND_MAP[rewardTierLevel]
: isCouponRewardType(rewardType)
? couponLabelMap[rewardType]
: null
if (!label) return null
return (
<BiroScript type="two" color="red" tilted="small">
{label}

View File

@@ -18,10 +18,14 @@ export enum MembershipLevelEnum {
L7 = "L7",
}
export function isMembershipLevel(value: string): value is MembershipLevelEnum {
return Object.values(MembershipLevelEnum).includes(
value as MembershipLevelEnum
)
export const TIER_TO_FRIEND_MAP: Record<MembershipLevelEnum, string> = {
[MembershipLevelEnum.L1]: "New Friend",
[MembershipLevelEnum.L2]: "Good Friend",
[MembershipLevelEnum.L3]: "Close Friend",
[MembershipLevelEnum.L4]: "Dear Friend",
[MembershipLevelEnum.L5]: "Loyal Friend",
[MembershipLevelEnum.L6]: "True Friend",
[MembershipLevelEnum.L7]: "Best Friend",
}
export type MembershipLevel = keyof typeof MembershipLevelEnum

View File

@@ -37,3 +37,9 @@ export const RESTAURANT_REWARD_IDS = [
REWARD_IDS.FreeKidsDrink,
REWARD_IDS.FreeBreakfast,
] as const
export const COUPON_REWARD_TYPES = [
"Surprise",
"Campaign",
"Member-voucher",
] as const

View File

@@ -239,5 +239,3 @@ export const validateApiAllTiersSchema = z.record(
)
export type RedeemLocation = "Non-redeemable" | "On-site" | "Online"
export type RewardType = "Tier" | "Member-voucher" | "Surprise" | "Campaign"

View File

@@ -378,6 +378,7 @@ export const rewardQueryRouter = router({
...reward,
id: surprise.id,
rewardType: surprise.rewardType,
rewardTierLevel: undefined,
redeemLocation: surprise.redeemLocation,
coupons: "coupon" in surprise ? surprise.coupon || [] : [],
}

View File

@@ -1,5 +1,9 @@
import type { IconProps } from "@/types/components/icon"
import type { RESTAURANT_REWARD_IDS, REWARD_IDS } from "@/constants/rewards"
import type {
COUPON_REWARD_TYPES,
RESTAURANT_REWARD_IDS,
REWARD_IDS,
} from "@/constants/rewards"
export interface RewardIconProps extends IconProps {
rewardId: string
@@ -9,3 +13,5 @@ export interface RewardIconProps extends IconProps {
export type RewardId = (typeof REWARD_IDS)[keyof typeof REWARD_IDS]
export type RestaurantRewardId = (typeof RESTAURANT_REWARD_IDS)[number]
export type CouponRewardType = (typeof COUPON_REWARD_TYPES)[number]

View File

@@ -0,0 +1,5 @@
import { MembershipLevelEnum } from "@/constants/membershipLevels"
export function isMembershipLevel(value: string): value is MembershipLevelEnum {
return Object.values(MembershipLevelEnum).some((level) => level === value)
}

View File

@@ -1,6 +1,11 @@
import { RESTAURANT_REWARD_IDS, REWARD_IDS } from "@/constants/rewards"
import {
COUPON_REWARD_TYPES,
RESTAURANT_REWARD_IDS,
REWARD_IDS,
} from "@/constants/rewards"
import type {
CouponRewardType,
RestaurantRewardId,
RewardId,
} from "@/types/components/myPages/rewards"
@@ -40,3 +45,9 @@ export function isRestaurantOnSiteTierReward(
): boolean {
return isOnSiteTierReward(reward) && isRestaurantReward(reward.reward_id)
}
export function isCouponRewardType(
type: RewardWithRedeem["rewardType"]
): type is CouponRewardType {
return COUPON_REWARD_TYPES.some((t) => t === type)
}