✨ 기억보다 기록을/프로젝트
20241118(월) ▶️ 굿즈샵페이지 Badge 공통 컴포넌트 만들기
서카츄
2024. 11. 19. 00:05
Badge는 무료배송, 인기, best 등을 표시하기 위해서 사용했다!
공통 컴포넌트로 유연성 있게 만들어 보았다.
뱃지 계산 로직
//utils/calculateBadge.ts
import type { BadgeFields } from "@/types";
export const calculateBadge = ({
shipping_type,
review_count,
rating,
}: BadgeFields) => {
const badges: string[] = [];
if (shipping_type === "무료배송") badges.push("무료배송");
const hasEnoughReviews = review_count && review_count >= 10;
const hasHighRating = rating && rating >= 4;
if (hasEnoughReviews && hasHighRating) badges.push("Best👍");
return badges;
};
//badge color 설정
export const getBadgeColor = (badge: string) => {
switch (badge) {
case "무료배송":
return "bg-purple";
case "Best👍":
return "bg-orange";
default:
return "bg-gray-500";
}
};
`shipping_type` : 무료배송인지 아닌지 여부
`review_count` : 리뷰 수
`rating` : 별점 평균
const badges: string[] = [];
처음에는 빈 배열로 시작해서 조건에 따라 빈 배열에 넣어준다.
if (shipping_type === "무료배송") badges.push("무료배송");
const hasEnoughReviews = review_count && review_count >= 10;
const hasHighRating = rating && rating >= 4;
if (hasEnoughReviews && hasHighRating) badges.push("Best👍");
`shipping_type` 이 무료배송이면 배열에 무료배송을 넣어준다.
`Best` 조건은 리뷰평점이 4.5이상, 리뷰가 10개 이상으로 카운트 했다.
조건이 전부 충족하면, Best를 넣어준다.
//badge color 설정
export const getBadgeColor = (badge: string) => {
switch (badge) {
case "무료배송":
return "bg-purple";
case "Best👍":
return "bg-orange";
default:
return "bg-gray-500";
}
};
`switch` 문을 사용해서 조건에 따라 다른 배경색을 반환해준다.
//Badge.tsx
import type { BadgeItemProps } from "@/types";
import { calculateBadge, getBadgeColor } from "@/utils/calculateBadge";
const Badge = ({ item }: BadgeItemProps) => {
const [averageRating, setAverageRating] = useState(0);
useEffect(() => {
const fetchRating = async () => {
try {
const rating = await getAverageRating(item.id);
setAverageRating(rating);
} catch (error) {
if (error instanceof Error) {
console.log(`평점 조회에 실패했습니다 : ,${error.message}`);
}
}
};
fetchRating();
}, [item.id]);
const badges = calculateBadge({ ...item, rating: averageRating });
if (badges.length === 0) return null;
return (
<div className="flex items-center gap-1 mt-4 mb-1">
{badges.map((badge) => (
<span
key={badge}
className={`text-xs px-2 py-1 rounded-md text-white ${getBadgeColor(
badge
)}`}
>
{badge}
</span>
))}
</div>
);
};
export default Badge;
리뷰 평점은 review의 테이블이 별도로 있어서 review의 내용을 넘겨줘야 한다.
그래서 useEffect로 수파베이스에 있는 review의 테이블을 가져와서 평점 계산한 함수를 가져온 다음 state에 넣어준다.
const badges = calculateBadge({ ...item, rating: averageRating });
if (badges.length === 0) return null;
item안에 리뷰 평균을 계산한 rating도 같이 넘겨줘야 해서
스프레드 연산자로 item과 함께 rating을 같이 넣어준다.
담은 내용을 `calculateBadge` 함수에 담아서 넘겨주고, 뱃지가 없으면 렌더링 하지 않는다.
<span
key={badge}
className={`text-xs px-2 py-1 rounded-md text-white ${getBadgeColor(
badge
)}`}
>
{badge}
</span>
`getBadgeColor`에 있는 조건에 따라 bg를 설정해준다.
적용 결과
평점이 4이상이고, 리뷰가 10개 이상이면 Best를,
무료배송이면 무료배송 뱃지가 잘 나온다.
아무것도 없으면 빈 공간으로 나온다😊