+
{
{categoryName}
- {productItem.title}
+ {productItem.title}
- {productItem.chip}
+
+ {productItem.chip}
+
-
- {productItem.cpu}
-
-
- {productItem.gpu}
-
-
- {productItem.storage}
-
-
- {productItem.memory}
-
-
- {productItem.color}
-
+ {productItem.cpu}
+ {productItem.gpu}
+ {productItem.storage}
+ {productItem.memory}
+ {productItem.color}
-
-
- {productItem.discountPercentage}%
-
-
-
{convertToLocalFormat(productItem.currentPrice)}원
+
+
+ {convertToLocalFormat(productItem.currentPrice)}원
+
diff --git a/src/features/search/components/searchResult/index.tsx b/src/features/search/components/searchResult/index.tsx
index cdd02fc..8c208ad 100644
--- a/src/features/search/components/searchResult/index.tsx
+++ b/src/features/search/components/searchResult/index.tsx
@@ -1,10 +1,12 @@
+/* eslint-disable @typescript-eslint/no-floating-promises */
'use client';
import { CategoryType } from '@/features/category/constants';
import { useGetSearchResult } from '../../hooks/useSearchResult';
import { FilterProperty } from '../../api/getFilterProperty';
-import queryString from 'query-string';
import { SearchResultItem } from './Item';
+import { Button } from '@/shared/components/shadcn/ui/button';
+import { Text } from '@/shared/components/shadcn/Text';
interface SearchResultProps {
category: CategoryType;
@@ -12,15 +14,33 @@ interface SearchResultProps {
}
export const SearchResultList = ({ category, params }: SearchResultProps) => {
- const { data: productData } = useGetSearchResult(category, params);
+ const { data, hasNextPage, fetchNextPage } = useGetSearchResult(category, params);
+ const productData = data.pages.map((page) => page.data).flat();
+
+ const handleClickNextPage = () => {
+ fetchNextPage();
+ };
+
+ console.log(hasNextPage);
return (
-
-
- {productData?.data.map((productItem) => {
+
+
+ {productData.map((productItem) => {
return ;
})}
+ {hasNextPage ? (
+
+ ) : (
+
+
+ 마지막 페이지입니다.
+
+
+ )}
);
};
diff --git a/src/features/search/hooks/useSearchResult.ts b/src/features/search/hooks/useSearchResult.ts
index 6a0cee8..44e03f5 100644
--- a/src/features/search/hooks/useSearchResult.ts
+++ b/src/features/search/hooks/useSearchResult.ts
@@ -1,4 +1,4 @@
-import { useSuspenseQuery, UseSuspenseQueryResult } from '@tanstack/react-query';
+import { InfiniteData, useSuspenseInfiniteQuery, UseSuspenseInfiniteQueryResult } from '@tanstack/react-query';
import { FilterProperty } from '../api/getFilterProperty';
import { CategoryType } from '@/features/category/constants';
import { getSearchResult, GetSearchResultResponse } from '../api/getSearchResult';
@@ -6,9 +6,17 @@ import { getSearchResult, GetSearchResultResponse } from '../api/getSearchResult
export const useGetSearchResult = (
category: CategoryType,
property: FilterProperty,
-): UseSuspenseQueryResult => {
- return useSuspenseQuery({
+): UseSuspenseInfiniteQueryResult> => {
+ return useSuspenseInfiniteQuery({
queryKey: ['search', category, property],
- queryFn: () => getSearchResult(category, property),
+ queryFn: ({ pageParam }) => getSearchResult(category, property, pageParam),
+ initialPageParam: 1,
+ getNextPageParam: (lastPage) => {
+ if (lastPage.pageInfo.lastPage === lastPage.pageInfo.currentPage) {
+ return undefined;
+ }
+
+ return lastPage.pageInfo.currentPage + 1;
+ },
});
};
diff --git a/src/shared/assets/Icons.tsx b/src/shared/assets/Icons.tsx
new file mode 100644
index 0000000..8d1e49f
--- /dev/null
+++ b/src/shared/assets/Icons.tsx
@@ -0,0 +1,12 @@
+import { SVGProps } from 'react';
+
+export function Triangle(props: SVGProps) {
+ return (
+
+ );
+}
diff --git a/src/shared/components/DiscountBadge/index.tsx b/src/shared/components/DiscountBadge/index.tsx
new file mode 100644
index 0000000..ec96862
--- /dev/null
+++ b/src/shared/components/DiscountBadge/index.tsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { Text } from '@/shared/components/shadcn/Text';
+import { Triangle } from '@/shared/assets/Icons';
+
+const DiscountBadge = ({ discountPercentage }: { discountPercentage: number }) => {
+ const getBadgeContent = () => {
+ switch (true) {
+ case discountPercentage < 0:
+ return (
+
+
+
+ {discountPercentage}%
+
+
+ );
+ case discountPercentage > 0:
+ return (
+
+
+
+ +{discountPercentage}%
+
+
+ );
+
+ case discountPercentage === 0:
+ return (
+
+ 변동없음
+
+ );
+ default:
+ return null;
+ }
+ };
+
+ return <>{getBadgeContent()}>;
+};
+
+export default DiscountBadge;
diff --git a/src/shared/components/shadcn/ui/label.tsx b/src/shared/components/shadcn/ui/label.tsx
index f27c69a..44401f6 100644
--- a/src/shared/components/shadcn/ui/label.tsx
+++ b/src/shared/components/shadcn/ui/label.tsx
@@ -1,26 +1,19 @@
-"use client"
+'use client';
-import * as React from "react"
-import * as LabelPrimitive from "@radix-ui/react-label"
-import { cva, type VariantProps } from "class-variance-authority"
+import * as React from 'react';
+import * as LabelPrimitive from '@radix-ui/react-label';
+import { cva, type VariantProps } from 'class-variance-authority';
-import { cn } from "@/shared/lib/tailwind/utils"
+import { cn } from '@/shared/lib/tailwind/utils';
-const labelVariants = cva(
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
-)
+const labelVariants = cva('text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70');
const Label = React.forwardRef<
React.ElementRef,
- React.ComponentPropsWithoutRef &
- VariantProps
+ React.ComponentPropsWithoutRef & VariantProps
>(({ className, ...props }, ref) => (
-
-))
-Label.displayName = LabelPrimitive.Root.displayName
+
+));
+Label.displayName = LabelPrimitive.Root.displayName;
-export { Label }
+export { Label };
diff --git a/src/shared/components/shadcn/ui/toggle.tsx b/src/shared/components/shadcn/ui/toggle.tsx
index ce3ccc5..94c6971 100644
--- a/src/shared/components/shadcn/ui/toggle.tsx
+++ b/src/shared/components/shadcn/ui/toggle.tsx
@@ -7,12 +7,12 @@ import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/shared/lib/tailwind/utils';
const toggleVariants = cva(
- 'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-30',
+ 'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-primary hover:text-primary-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-30',
{
variants: {
variant: {
default: 'bg-transparent',
- outline: 'border border-input bg-transparent hover:bg-accent hover:text-accent-foreground',
+ outline: 'border border-input bg-transparent hover:bg-primary hover:text-white',
},
size: {
default: 'h-10 px-3',
diff --git a/tailwind.config.ts b/tailwind.config.ts
index 0703a42..0c3e325 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -18,6 +18,7 @@ const config = {
extend: {
colors: {
badge: '#F45151',
+ badgeBackground: '#F9F2F2',
border: 'hsl(var(--border))',
input: 'hsl(var(--input))',
ring: 'hsl(var(--ring))',