Skip to content

Commit

Permalink
GLUE-225-블로그페이지-api-연결 (#71)
Browse files Browse the repository at this point in the history
* feat: 변경된 DTO에 따른 로직 변경 및 blogId 전역관리

* chore: 변수명 변경

* Update src/components/UserContext/index.tsx

Co-authored-by: SeongMin Kim <[email protected]>

* refactor: 성능 최적화를 위한 useMemo 사용

* fix: 빌드 오류

* fix: 경로 오류 수정

* refactor: userContextWrapper 파일 구조 리팩토링

* fix: 빌드 오류 수정

* feat: blog api 연결

* feat: 앨범 렌더링을 위한 Slider 구현

* feat: 확대 및 축소 아이콘 추가

* refactor: pr 리뷰 반영

* refactor: useSlider구현을 통한 비지니스 로직 분리

---------

Co-authored-by: SeongMin Kim <[email protected]>
  • Loading branch information
yeyounging and Collection50 authored Jun 10, 2024
1 parent af4615f commit 5fffbdb
Show file tree
Hide file tree
Showing 19 changed files with 296 additions and 44 deletions.
47 changes: 47 additions & 0 deletions src/app/blog/[blogId]/components/Albums/Slider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use client';

import React from 'react';
import Image from 'next/image';
import { Button } from '@/components/Common';
import { useSlider } from './useSlider';

export default function Slider({ photos }: { photos: string[] }) {
const temp = '/tempImage/6.jpg';
const { currentIndex, nextSlide, prevSlide } = useSlider(photos.length);

return (
<div className="relative w-full overflow-hidden shadow-lg">
<div
className="flex transform transition-transform duration-1000 ease-in-out"
style={{ transform: `translateX(-${currentIndex * 100}%)` }}
>
{photos.map((photo) => (
<div key={photo} className="relative flex-none w-1/5 h-200">
<div className="w-full h-full">
<Image
alt="photo"
src={photo || temp}
layout="fill"
objectFit="cover"
/>
</div>
</div>
))}
</div>
<div className="absolute inset-0 flex items-center justify-between px-4">
<Button
className="p-2 bg-[#f1efef] rounded-full opacity-50 hover:opacity-90"
onClick={prevSlide}
>
&lt; Prev
</Button>
<Button
className="p-2 bg-[#f1efef] rounded-full opacity-50 hover:opacity-90"
onClick={nextSlide}
>
Next &gt;
</Button>
</div>
</div>
);
}
31 changes: 14 additions & 17 deletions src/app/blog/[blogId]/components/Albums/index.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
import Image from 'next/image';
import { range } from '@/utils';
'use client';

import { useBlogPageContext } from '../BlogFetcher/BlogContext';
import Slider from './\bSlider';

export default function Albums() {
const imageCount = 5;
const images = range(0, imageCount);
const {
blogPostItem: { postItems },
} = useBlogPageContext();

// FIXME: photoUrl 적용
const photos = Array(20)
.fill(null)
.map((_, index) => postItems[index]?.photo || '/tempImage/6.jpg');

return (
<article className="flex flex-col px-100 items-start">
<article className="flex flex-col w-full gap-20 px-100 items-start">
<div className="flex flex-col justify-center items-center">
<div className="font-extrabold text-4xl">Albums</div>
<p className="w-135 h-3 bg-primary mb-2" />
<p className="w-145 h-3 bg-primary mb-2" />
</div>
<div className="flex flex-row gap-10 py-40">
{images.map((image) => (
<div key={image} className="w-150 h-150 relative overflow-hidden">
<Image
alt={`Image ${image}`}
src={`/tempImage/${image}.jpg`}
layout="fill"
objectFit="cover"
/>
</div>
))}
</div>
<Slider photos={photos} />
</article>
);
}
19 changes: 19 additions & 0 deletions src/app/blog/[blogId]/components/Albums/useSlider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useState, useCallback } from 'react';

export function useSlider(totalSlides: number) {
const [currentIndex, setCurrentIndex] = useState(0);

const nextSlide = useCallback(() => {
setCurrentIndex((prevIndex) =>
prevIndex === Math.ceil(totalSlides / 5) - 1 ? 0 : prevIndex + 1,
);
}, [totalSlides]);

const prevSlide = useCallback(() => {
setCurrentIndex((prevIndex) =>
prevIndex === 0 ? Math.ceil(totalSlides / 5) - 1 : prevIndex - 1,
);
}, [totalSlides]);

return { currentIndex, nextSlide, prevSlide };
}
11 changes: 8 additions & 3 deletions src/app/blog/[blogId]/components/BlogBackground/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
'use client';

import Image from 'next/image';
import bg from '../../../../../../public/images/bg-temp.jpeg';
import { useBlogPageContext } from '../BlogFetcher/BlogContext';

export default function BlogBackground() {
const description = 'Just keep swimming 🏄🏿‍♂️';
const {
blogInfo: { description, background },
} = useBlogPageContext();

return (
<div className="w-full h-screen">
<div className="relative w-full h-full group">
<Image
src={bg}
src={background}
alt="background"
layout="fill"
objectFit="cover"
Expand Down
15 changes: 15 additions & 0 deletions src/app/blog/[blogId]/components/BlogFallback/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use client';

import { Button } from '@/components/Common';
import { useErrorBoundaryContext } from '@/react-utils/ErrorboundaryContext';
import { StrictPropsWithChildren } from '@/types';

export default function BlogFallback({ children }: StrictPropsWithChildren) {
const { error, resetErrorBoundary } = useErrorBoundaryContext();

if (error !== null) {
// TODO: 변경
return <Button onClick={() => resetErrorBoundary()}>다시 시도하기</Button>;
}
return children;
}
9 changes: 9 additions & 0 deletions src/app/blog/[blogId]/components/BlogFetcher/BlogContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use client';

import { generateContext } from '@/react-utils';
import { BlogPageInfo } from './types';

export const [BlogPageProvider, useBlogPageContext] =
generateContext<BlogPageInfo>({
name: 'blog-page',
});
7 changes: 7 additions & 0 deletions src/app/blog/[blogId]/components/BlogFetcher/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { http } from '@/api';
import { BlogPageInfo } from './types';

export const getBlogPageInfo = (blogId: number) =>
http.get<BlogPageInfo>({
url: `/blogs/${blogId}`,
});
16 changes: 16 additions & 0 deletions src/app/blog/[blogId]/components/BlogFetcher/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use client';

import { ReactNode } from 'react';
import { BlogPageProvider } from './BlogContext';
import { useBlogPage } from './queries';

interface BlogPageFetcherProps {
children: ReactNode;
blogId: number;
}

export function BlogPageFetcher({ children, blogId }: BlogPageFetcherProps) {
const { data } = useBlogPage(blogId);

return <BlogPageProvider {...data}>{children}</BlogPageProvider>;
}
12 changes: 12 additions & 0 deletions src/app/blog/[blogId]/components/BlogFetcher/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use client';

import { useSuspenseQuery } from '@tanstack/react-query';
import { getBlogPageInfo } from './api';

export const useBlogPage = (blogId: number) =>
useSuspenseQuery({
queryKey: ['blog-page', blogId],
queryFn: () => getBlogPageInfo(blogId),
refetchOnMount: false,
select: (data) => data.result,
});
21 changes: 21 additions & 0 deletions src/app/blog/[blogId]/components/BlogFetcher/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export interface BlogPageInfo {
blogInfo: {
title: string;
description: string;
profile: string;
background: string;
};
blogPostItem: {
postItems: [
{
blogId: number;
postId: number;
title: string;
preview: string;
photo: string;
},
];
hashtagNames: string[];
};
memberName: string;
}
7 changes: 6 additions & 1 deletion src/app/blog/[blogId]/components/BlogHeader/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
'use client';

import { Nav, NavigationIcons } from '@/components/Common';
import { useBlogPageContext } from '../BlogFetcher/BlogContext';

export default function BlogHeader({
children,
}: {
children: React.ReactNode;
}) {
const title = ' do the best Zl금 ';
const {
blogInfo: { title },
} = useBlogPageContext();

return (
<div className="relative">
Expand Down
14 changes: 11 additions & 3 deletions src/app/blog/[blogId]/components/ProfileBox/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
'use client';

import Image from 'next/image';
import { Button } from '@/components/Common';
import bg from '../../../../../../public/images/bg-temp.jpeg';
import { useBlogPageContext } from '../BlogFetcher/BlogContext';

export default function ProfileBox() {
const {
blogInfo: { profile },
memberName,
} = useBlogPageContext();

return (
<section className="flex flex-col items-center mr-50">
<div className="relative w-250 h-300 my-10 ">
<Image src={bg} alt="profile" layout="fill" objectFit="cover" />
<Image src={profile} alt="profile" layout="fill" objectFit="cover" />
</div>
<div className="text-xl text-center mt-10 ">주에</div>
<div className="text-xl text-center mt-10 ">{memberName}</div>
<p className="w-200 h-3 bg-primary" />
{/* FIXME: 자신의 블로그일경우 off */}
<Button className="bg-primary text-white font-semibold w-120 h-30 m-25">
subscribe
</Button>
Expand Down
27 changes: 14 additions & 13 deletions src/app/blog/[blogId]/components/StoryBox/index.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
'use client';

import { HamburgerMenu } from '@/components/Common';
import { generateId } from '@/utils';
import { useBlogPageContext } from '../BlogFetcher/BlogContext';

export function Story() {
export function Story({ title, content }: { title: string; content: string }) {
return (
<div className="h-140">
<div className="h-30 text-xl font-bold ">보통의 일상</div>
<div className="h-30 text-xl font-bold ">{title}</div>
<div className="my-5 h-100 white-space:normal break-words text-overflow">
공포물을 별로 좋아하지 않는 나는 본래 파묘를 볼 계획이 없었지만, 다들
재밌다는 입소문과 900만 돌파라는 타이틀에 군중심리가 자극됐다. 걱정과는
달리 많이 무섭지는 않았다. 용두사미의 느낌이 있다던데 나는 처음부터
끝까지 재밌게 봤다. 영화관을 오랜만에 가서 이미 신나있기도 했고 유해진
애드립이 너무 재밌어서 계속 웃으면서 봤다. 다음은 듄 보러 또 와야겠다.
티모시가 그렇게 또 놀
{content}
</div>
</div>
);
}

export default function StoryBox() {
const {
blogPostItem: { postItems },
} = useBlogPageContext();

return (
<section className="w-full px-100">
<header className="flex flex-row items-center justify-between w-full pr-10">
Expand All @@ -25,14 +28,12 @@ export default function StoryBox() {
<p className="w-130 h-3 bg-primary mb-2" />
<p className="w-140 h-3 bg-primary mb-2" />
</div>

<HamburgerMenu />
</header>
<article className="w-full grid grid-cols-2 gap-30 mt-40">
<Story />
<Story />
<Story />
<Story />
{postItems.map(({ preview, title }) => (
<Story key={generateId()} title={title} content={preview} />
))}
</article>
</section>
);
Expand Down
11 changes: 9 additions & 2 deletions src/app/blog/[blogId]/components/Tags/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
'use client';

import { useBlogPageContext } from '../BlogFetcher/BlogContext';

export default function Tags() {
const tags = ['technology', 'daily', 'puppy', 'cooking', 'React'];
const {
blogPostItem: { hashtagNames },
} = useBlogPageContext();

return (
<div className="px-30 py-20 mr-50">
<div className="font-semibold text-2xl">tags.</div>
<div className="h-1 w-200 bg-[#323131] m-3" />
<ul className="py-20 text-[20px]">
{tags.map((tag) => (
{hashtagNames.map((tag) => (
<li key={tag} className="py-5">
# {tag}
</li>
Expand Down
25 changes: 21 additions & 4 deletions src/app/blog/[blogId]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
import { AsyncBoundaryWithQuery } from '@/react-utils';
import type { Metadata } from 'next';
import BlogFallback from './components/BlogFallback';
import { BlogPageFetcher } from './components/BlogFetcher';

export const metadata: Metadata = {
title: 'myblog',
description: 'Glue - myblog',
title: 'Glue - blog',
description: 'Glue - blog',
};

export default function layout({ children }: { children: React.ReactNode }) {
return <main>{children}</main>;
export default function layout({
children,
params: { blogId },
}: {
children: React.ReactNode;
params: { blogId: number };
}) {
return (
<AsyncBoundaryWithQuery pendingFallback={<div> Loading...</div>}>
<BlogFallback>
<BlogPageFetcher blogId={blogId}>
<main className="text-[#171717]">{children}</main>;
</BlogPageFetcher>
</BlogFallback>
</AsyncBoundaryWithQuery>
);
}
2 changes: 1 addition & 1 deletion src/app/blog/[blogId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function Page() {
<ProfileBox />
<StoryBox />
</section>
<section className="flex flex-row m-100">
<section className="flex flex-row m-100 h-full">
<Tags />
<Albums />
</section>
Expand Down
Loading

0 comments on commit 5fffbdb

Please sign in to comment.