Skip to content

Commit 89b511a

Browse files
committed
feat: 배너 api 연동
1 parent 64c1610 commit 89b511a

6 files changed

Lines changed: 108 additions & 103 deletions

File tree

src/app/page.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CarouselWithDots } from '@/components/banner-carousel';
1+
import BannerCarouselContainer from '@/components/banner-carousel';
22
import {
33
RecommendedCategoryCard,
44
RecommendCarousel,
@@ -29,13 +29,25 @@ export default async function Home() {
2929
<div className="flex flex-col items-center">
3030
<MainHeader />
3131

32-
<CarouselWithDots />
32+
<Suspense fallback={<div>Loading...</div>}>
33+
<BannerCarouselContainer />
34+
</Suspense>
3335
<Suspense fallback={<div>Loading...</div>}>
3436
<RecommendCategoryContainer />
3537
</Suspense>
3638

3739
<Suspense fallback={<div>Loading...</div>}>
38-
<RecommendProductContainer />
40+
<RecommendProductContainer
41+
endpoint="/products/special-sale"
42+
heading="특가 상품"
43+
/>
44+
</Suspense>
45+
46+
<Suspense fallback={<div>Loading...</div>}>
47+
<RecommendProductContainer
48+
endpoint="/products/recommend"
49+
heading="추천 상품"
50+
/>
3951
</Suspense>
4052

4153
<RecommendedBrandContainer brands={BRANDS} productLists={[p1, p2, p3]} />
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { api } from '@/lib/api-client';
2+
import { Advertisement } from '@/types/domain/advertisement';
3+
import { CarouselWithDots } from './carousel-with-dots';
4+
5+
export default async function BannerCarouselContainer() {
6+
const advertisements = await api.get<Advertisement[]>('/advertisements/home');
7+
8+
return <CarouselWithDots advertisements={advertisements} />;
9+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
'use client';
2+
3+
import { useState } from 'react';
4+
import Image from 'next/image';
5+
import {
6+
Carousel,
7+
CarouselContent,
8+
CarouselItem,
9+
type CarouselApi,
10+
} from '@/components/ui/carousel';
11+
import { useCarouselDots } from './use-carousel-dots';
12+
import { DotNavigation } from './dot-navigation';
13+
import Autoplay from 'embla-carousel-autoplay';
14+
import { Advertisement } from '@/types/domain/advertisement';
15+
16+
interface CarouselWithDotsProps {
17+
advertisements: Advertisement[];
18+
}
19+
20+
export function CarouselWithDots({ advertisements }: CarouselWithDotsProps) {
21+
const [api, setApi] = useState<CarouselApi>();
22+
const { current, count, scrollTo } = useCarouselDots(api);
23+
24+
return (
25+
<div className="w-screen max-w-200">
26+
<Carousel
27+
setApi={setApi}
28+
opts={{
29+
loop: true,
30+
}}
31+
plugins={[
32+
Autoplay({
33+
delay: 3000,
34+
stopOnInteraction: false,
35+
}),
36+
]}
37+
>
38+
<CarouselContent className="m-0 max-h-125 w-full">
39+
{advertisements.map((item) => (
40+
<CarouselItem key={item.id} className="p-0">
41+
<div className="relative aspect-380/275 h-full w-full overflow-hidden">
42+
<Image
43+
src={item.imageUrl}
44+
alt={item.title}
45+
fill
46+
className="object-cover"
47+
priority
48+
/>
49+
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
50+
<div className="absolute bottom-0 left-0 right-0 p-6 text-white">
51+
<h3 className="mb-2 text-2xl font-black break-keep">
52+
{item.title}
53+
</h3>
54+
<p className="text-lg font-medium break-keep opacity-90">
55+
{item.description}
56+
</p>
57+
</div>
58+
</div>
59+
</CarouselItem>
60+
))}
61+
</CarouselContent>
62+
</Carousel>
63+
<DotNavigation count={count} current={current} onDotClick={scrollTo} />
64+
</div>
65+
);
66+
}
Lines changed: 1 addition & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1 @@
1-
'use client';
2-
3-
import { useState } from 'react';
4-
import Link from 'next/link'; // Link 태그 추가
5-
import {
6-
Carousel,
7-
CarouselContent,
8-
CarouselItem,
9-
type CarouselApi,
10-
} from '@/components/ui/carousel';
11-
import { useCarouselDots } from './use-carousel-dots';
12-
import { DotNavigation } from './dot-navigation';
13-
import Autoplay from 'embla-carousel-autoplay';
14-
15-
export function CarouselWithDots() {
16-
const [api, setApi] = useState<CarouselApi>();
17-
const { current, count, scrollTo } = useCarouselDots(api);
18-
19-
const bannerContent = [
20-
{
21-
title: '“프롬프트 엔지니어링 (aka 구걸)”',
22-
desc: '"제발 한 번만 돌아가게 해줘"라고 정중하게 부탁해서 얻어낸 코드입니다. AI는 예의 바른 사람을 좋아하거든요.',
23-
handle: '@bk-git-hub',
24-
link: 'https://github.com/bk-git-hub',
25-
},
26-
{
27-
title: '“버그는 죽지 않는다, 다만 숨을 뿐”',
28-
desc: '버그는 우리와 함께 살아가는 동반자입니다. 죽이려 하지 마세요. 그냥 다른 곳으로 옮기세요.',
29-
handle: '@Seoje1405',
30-
link: 'https://github.com/Seoje1405',
31-
},
32-
{
33-
title: '“할루시네이션도 하나의 기능입니다”',
34-
desc: 'AI가 존재하지 않는 라이브러리를 사용했다고요? 그건 저희가 앞으로 만들겠다는 미래지향적 비전입니다.',
35-
handle: '@bk-git-hub',
36-
link: 'https://github.com/bk-git-hub',
37-
},
38-
{
39-
title: '“커밋 메시지 ‘fix’는 기도의 한 종류”',
40-
desc: '아무것도 안 고쳤지만 제발 이번엔 배포가 성공하길 바라는 개발자의 간절한 염원입니다.',
41-
handle: 'Seoje1405',
42-
link: 'https://github.com/Seoje1405',
43-
},
44-
45-
{
46-
title: '“완벽한 코드는 배포하지 않은 코드”',
47-
desc: '세상에 돌아가는 쓰레기는 있어도 완벽한 코드는 없습니다. 돌아가면 일단 퇴근하십시오.',
48-
handle: '@bk-git-hub',
49-
link: 'https://github.com/bk-git-hub',
50-
},
51-
];
52-
53-
return (
54-
<div className="w-screen max-w-200">
55-
<Carousel
56-
setApi={setApi}
57-
opts={{
58-
loop: true,
59-
}}
60-
plugins={[
61-
Autoplay({
62-
delay: 3000,
63-
stopOnInteraction: false,
64-
}),
65-
]}
66-
>
67-
<CarouselContent className="m-0 max-h-125 w-full">
68-
{bannerContent.map((item, i) => (
69-
<CarouselItem key={i} className="p-0">
70-
<Link
71-
href={item.link}
72-
target="_blank"
73-
className="block h-full w-full transition-transform outline-none active:scale-95"
74-
>
75-
<div className="bg-card text-card-foreground hover:bg-accent flex aspect-380/275 h-full w-full flex-col items-center justify-center border-4 p-6 text-center transition-colors">
76-
<span className="mb-2 text-xs font-bold tracking-widest uppercase opacity-60">
77-
{item.handle}
78-
</span>
79-
<h3 className="mb-4 text-2xl font-black break-keep italic underline decoration-yellow-400 underline-offset-4">
80-
{item.title}
81-
</h3>
82-
<p className="text-lg font-medium break-keep opacity-90">
83-
{item.desc}
84-
</p>
85-
<span className="mt-4 text-[10px] font-bold opacity-40 group-hover:opacity-100">
86-
CLICK TO VISIT GITHUB
87-
</span>
88-
</div>
89-
</Link>
90-
</CarouselItem>
91-
))}
92-
</CarouselContent>
93-
</Carousel>
94-
<DotNavigation count={count} current={current} onDotClick={scrollTo} />
95-
</div>
96-
);
97-
}
1+
export { default } from './banner-carousel-container';

src/components/recommend-carousel/recommend-product-container.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,18 @@ import { RecommendedProductCard } from './recommended-product-card';
44
import { RecommendCarouselItem } from './recommend-carousel-item';
55
import { RecommendCarousel } from './recommend-carousel';
66

7-
export default async function RecommendProductContainer() {
8-
const products = await api.get<Product[]>('/products/recommend');
7+
interface RecommendProductContainerProps {
8+
endpoint: string;
9+
heading: string;
10+
}
11+
12+
export default async function RecommendProductContainer({
13+
endpoint,
14+
heading,
15+
}: RecommendProductContainerProps) {
16+
const products = await api.get<Product[]>(endpoint);
917
return (
10-
<RecommendCarousel heading="추천 상품">
18+
<RecommendCarousel heading={heading}>
1119
{products.map((product) => (
1220
<RecommendCarouselItem key={product.id}>
1321
<RecommendedProductCard productInfo={product} />

src/types/domain/advertisement.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export interface Advertisement {
2+
id: number;
3+
imageUrl: string;
4+
title: string;
5+
description: string;
6+
}

0 commit comments

Comments
 (0)