Skip to content

Commit

Permalink
Merge pull request #42 from dnd-side-project/feat-infinite-scroll
Browse files Browse the repository at this point in the history
  • Loading branch information
seondal authored Sep 8, 2023
2 parents 4ee89c8 + b7c47a1 commit 90bdab8
Show file tree
Hide file tree
Showing 30 changed files with 272 additions and 186 deletions.
5 changes: 2 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@
.env

# Next-PWA
public/sw.js
public/workbox-*.js
public/sw.js.map
public/*.js
public/*.js.map
6 changes: 3 additions & 3 deletions public/icons/bookmark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions public/images/profile_default.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 8 additions & 3 deletions src/apis/apis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ export const getPoseDetail = (poseId: number) =>

export const getPoseTalk = () => publicApi.get<PoseTalkResponse>('/pose/talk');

export const getPoseFeed = (peopleCount: number, frameCount: number, tags: string) =>
publicApi.get<PoseFeedResponse>(`/pose`, {
export const getPoseFeed = async (
peopleCount: number,
frameCount: number,
tags: string,
pageNumber: number
) =>
await publicApi.get<PoseFeedResponse>(`/pose`, {
params: {
frameCount,
pageNumber: 0,
pageNumber,
peopleCount,
tags,
},
Expand Down
23 changes: 19 additions & 4 deletions src/apis/queries.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { UseQueryOptions, useQuery } from '@tanstack/react-query';
import {
UseInfiniteQueryOptions,
UseQueryOptions,
useInfiniteQuery,
useQuery,
} from '@tanstack/react-query';

import {
FilterTagsResponse,
Expand Down Expand Up @@ -30,12 +35,22 @@ export const usePoseTalkQuery = (options?: UseQueryOptions<PoseTalkResponse>) =>

export const usePoseFeedQuery = (
{ peopleCount, frameCount, tags }: FilterState,
options?: UseQueryOptions<PoseFeedResponse>
options?: UseInfiniteQueryOptions<PoseFeedResponse>
) =>
useQuery<PoseFeedResponse>(
useInfiniteQuery<PoseFeedResponse>(
['poseFeed', peopleCount, frameCount, tags],
() => getPoseFeed(peopleCount, frameCount, tags.join(',')),
({ pageParam = '' }) => getPoseFeed(peopleCount, frameCount, tags.join(','), pageParam),
{
getNextPageParam: (lastPage) => {
let target = lastPage.filteredContents;
if (lastPage.recommendation) {
target = lastPage.recommendedContents;
} else {
target = lastPage.filteredContents;
}
if (target.last) return false;
return target.number + 1;
},
...options,
}
);
Expand Down
6 changes: 5 additions & 1 deletion src/app/(Main)/components/MainHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ export default function MainHeader() {
<h4>PosePicker</h4>
</Link>
}
rightNode={<Image src="/icons/menu.svg" width={24} height={24} alt="24" />}
rightNode={
<Link href={'/menu'}>
<Image src="/icons/menu.svg" width={24} height={24} alt="24" />
</Link>
}
headerDownNode={<Tab />}
className="px-20"
/>
Expand Down
4 changes: 2 additions & 2 deletions src/app/(Main)/feed/components/PhotoList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface PhotoList {

export default function PhotoList({ data }: PhotoList) {
return (
<div className="columns-2 overflow-y-scroll py-16">
<>
{data ? (
data.map((item) => (
<Photo
Expand All @@ -20,6 +20,6 @@ export default function PhotoList({ data }: PhotoList) {
) : (
<Photo />
)}
</div>
</>
);
}
42 changes: 31 additions & 11 deletions src/app/(Main)/feed/page.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
'use client';

import Link from 'next/link';
import { useRouter, useSearchParams } from 'next/navigation';
import { useCallback } from 'react';

import EmptyCase from './components/EmptyCase';
import FilterSheet from './components/FilterSheet';
import FilterTab from './components/FilterTab';
import PhotoList from './components/PhotoList';
import { usePoseFeedQuery } from '@/apis';
import { Spacing } from '@/components/Spacing';
import { URL } from '@/constants/url';
import useDidMount from '@/hooks/useDidMount';
import useFilterState from '@/hooks/useFilterState';
import useIntersect from '@/hooks/useObserver';

export default function Feed() {
const params = useSearchParams();
const router = useRouter();

const { filterState, updateFilterState } = useFilterState();
const { data, isFetched } = usePoseFeedQuery(filterState);
const { data, fetchNextPage, hasNextPage, isLoading } = usePoseFeedQuery(filterState);

useDidMount(() => {
if (!params.get('filter')) return;
Expand All @@ -29,27 +31,45 @@ export default function Feed() {
router.replace('/feed');
});

const onIntersect = useCallback(async () => {
if (hasNextPage && !isLoading) {
await fetchNextPage();
}
}, [fetchNextPage, hasNextPage, isLoading]);

const target = useIntersect(onIntersect);

return (
<>
<FilterTab />
<Spacing size={56} />
<div>
{data?.recommendation && (
<Spacing size={40} />
<div className="h-fit overflow-y-scroll">
{data?.pages[0].recommendation ? (
<>
<EmptyCase
title={'신비한 포즈를 찾으시는군요!'}
text={'찾고 싶은 포즈를 저희에게 알려주세요.'}
button={'문의사항 남기기'}
path={
'https://docs.google.com/forms/d/e/1FAIpQLSeZuPZTXnO4rZ4k39SzXv96PWAW4gLcTYBrsRUrgRHSVV9Ldg/viewform?usp=sf_link'
}
path={URL.inquiry}
/>

<h4 className="mb-16">이런 포즈는 어때요?</h4>
<PhotoList data={data.recommendedContents.content} />
<div className="columns-2 py-16">
{data?.pages.map((page) => (
<PhotoList
key={page.recommendedContents.number}
data={page.recommendedContents.content}
/>
))}
</div>
</>
) : (
<div className="columns-2 py-16">
{data?.pages.map((page) => (
<PhotoList key={page.filteredContents.number} data={page.filteredContents.content} />
))}
</div>
)}
{isFetched ? <PhotoList data={data?.filteredContents.content} /> : <PhotoList />}
<div ref={target} className="h-1" />
</div>
<FilterSheet />
</>
Expand Down
8 changes: 5 additions & 3 deletions src/app/(Main)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import MainHeader from './components/MainHeader';
import { Spacing } from '@/components/Spacing';
import MainHeader from './components/MainHeader';
import { StrictPropsWithChildren } from '@/types';

export default function MainLayout({ children }: StrictPropsWithChildren) {
return (
<>
<Spacing size={80} />
<MainHeader />
<div className="px-20 py-16">{children}</div>
<div className="flex h-screen flex-col overflow-hidden px-20">
<Spacing size={100} />
{children}
</div>
</>
);
}
23 changes: 9 additions & 14 deletions src/app/(Main)/pick/components/PickSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,22 @@ export default function PickSection() {
};

return (
<section className="flex flex-col items-center">
<Spacing size={16} />
<div className="w-full">
<>
<div className="py-16">
<SelectionBasic
data={peopleCountList.slice(1)}
state={countState}
setState={setCountState}
/>
</div>

<Spacing size={16} />

<div className="flex h-460 w-full items-center justify-center bg-black">
<div className="relative flex h-460 w-300 items-center justify-center">
{true && <Lottie loop animationData={lottiePick} play />}
<div className="relative flex flex-1">
<div className="absolute inset-0 flex justify-center bg-black">
{isLoading && <Lottie loop animationData={lottiePick} play />}
<Image
src={image || '/images/image-frame.png'}
fill
alt="sample"
priority
loading="eager"
className={clsx({ hidden: isLoading }, 'cursor-pointer')}
className={clsx({ hidden: isLoading }, 'cursor-pointer object-contain')}
onClick={() =>
open(({ exit }) => (
<Popup>
Expand All @@ -71,17 +65,18 @@ export default function PickSection() {
</Popup>
))
}
alt="이미지"
/>
</div>
</div>

<Spacing size={100} />
<BottomFixedButton
className="bg-main-violet text-white"
onClick={handlePickClick}
disabled={isLoading}
>
{!!image ? '포즈 pick!' : '인원수 선택하고 포즈 pick!'}
</BottomFixedButton>
</section>
</>
);
}
10 changes: 6 additions & 4 deletions src/app/(Main)/talk/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { Spacing } from '@/components/Spacing';

export default function Talk() {
return (
<div>
<>
<div className="flex flex-1 flex-col items-center justify-center">
<TitleSection />
<TalkSection />
</div>
<Spacing size={80} />
<TitleSection />
<TalkSection />
</div>
</>
);
}
17 changes: 0 additions & 17 deletions src/app/(Sub)/bookmark/components/BookmarkHeader.tsx

This file was deleted.

10 changes: 2 additions & 8 deletions src/app/(Sub)/detail/[id]/components/DetailHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
'use client';
import Image from 'next/image';
import Link from 'next/link';

import IconButton from '@/components/Button/IconButton';
import { Header } from '@/components/Header';
import { Popup } from '@/components/Modal';
import { useOverlay } from '@/components/Overlay/useOverlay';
import CloseButton from '@/components/Header/CloseButton';

export default function DetailHeader() {
const { open } = useOverlay();
return (
<Header
leftNode={
<Link href="/feed">
<IconButton size="large">
<Image src="/icons/close.svg" width={24} height={24} alt="back" />
</IconButton>
</Link>
}
leftNode={<CloseButton />}
rightNode={
<IconButton
size="large"
Expand Down
30 changes: 0 additions & 30 deletions src/app/(Sub)/menu/components/InqueryModal.tsx

This file was deleted.

Loading

0 comments on commit 90bdab8

Please sign in to comment.