✨ 기억보다 기록을/프로젝트

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를,

무료배송이면 무료배송 뱃지가 잘 나온다.

아무것도 없으면 빈 공간으로 나온다😊