Skip to content

Commit

Permalink
[SP2] 프로젝트 목록 useQuery 적용 및 필터링 값 유지 (#256)
Browse files Browse the repository at this point in the history
* feat: queryClient 기본값 설정

* feat: 프로젝트 리스트 API 반환 타입 수정

* feat: 프로젝트 리스트 API useQuery 적용

* feat: 서스펜스 Fallback UI 컴포넌트 생성

* style: 프로젝트 카드 스타일 코드 수정

* style: 프로젝트 개수 스타일 코드 수정

* style: 프로젝트 목록 스타일 코드 수정

* feat: 프로젝트 필터값 세션 스토리지 저장

* feat: 최근 출시한 프로젝트 캐싱 데이터 사용

* feat: 프로젝트 목록 staleTime 지정

* feat: 세션 스토리지 훅 타입 지정

* style: Fallback UI 수정

* fix: 최근 출시한 프로젝트 useQuery 적용

* style: 필요없는 스타일 코드 제거

* feat : 프로젝트 캐러셀 SkeletonUI (#258)

* fix: 블로그 썸네일 옵셔널 체이닝 적용

---------

Co-authored-by: solar3070 <>
Co-authored-by: wooyoung <[email protected]>
  • Loading branch information
solar3070 and f0rever0 authored Nov 6, 2023
1 parent 81cca79 commit 74598ac
Show file tree
Hide file tree
Showing 25 changed files with 413 additions and 225 deletions.
13 changes: 5 additions & 8 deletions src/lib/api/remote/project.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import { BASE_URL, DEFAULT_TIMEOUT } from '@src/lib/constants/client';
import { BASE_URL } from '@src/lib/constants/client';
import axios from 'axios';
import qs from 'qs';
import {
GetProjectDetailResponse,
GetProjectListResponse,
ProjectAPI,
ProjectCategoryType,
ProjectPlatformType,
ProjectType,
} from '../../types/project';

const client = axios.create({
baseURL: BASE_URL,
timeout: DEFAULT_TIMEOUT,
});
const client = axios.create({ baseURL: BASE_URL });

const getProjectDetail = async (projectId: number): Promise<GetProjectDetailResponse> => {
const { data } = await client.get(`/projects/${projectId}`);
Expand All @@ -26,12 +23,12 @@ const getProjectDetail = async (projectId: number): Promise<GetProjectDetailResp
const getProjectList = async (
category: ProjectCategoryType,
platform: ProjectPlatformType,
): Promise<GetProjectListResponse> => {
): Promise<ProjectType[]> => {
const categoryParameter = category === ProjectCategoryType.ALL ? {} : { filter: category };
const platformParameter = platform === ProjectPlatformType.ALL ? {} : { platform };
const parameter = qs.stringify({ ...categoryParameter, ...platformParameter });
const { data } = await client.get(`/projects?${parameter}`);
return { projects: data };
return data;
};

export const remoteProjectAPI: ProjectAPI = {
Expand Down
6 changes: 1 addition & 5 deletions src/lib/types/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,10 @@ export interface GetProjectDetailResponse {
project: ProjectType;
}

export interface GetProjectListResponse {
projects: ProjectType[];
}

export interface ProjectAPI {
getProjectDetail(projectId: number): Promise<GetProjectDetailResponse>;
getProjectList(
category: ProjectCategoryType,
platform: ProjectPlatformType,
): Promise<GetProjectListResponse>;
): Promise<ProjectType[]>;
}
17 changes: 14 additions & 3 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import Head from 'next/head';
import { useRouter } from 'next/router';
import { Global } from '@emotion/react';
import { useEffect } from 'react';
import { useState } from 'react';
import { QueryClient, QueryClientProvider } from 'react-query';
import { ReactQueryDevtools } from 'react-query/devtools';
import SEO from '@src/components/common/SEO';
import GoogleTagManagerNoscript from '@src/components/googleTagManager/Noscript';
import GoogleTagManagerScript from '@src/components/googleTagManager/Script';
Expand All @@ -14,15 +14,25 @@ import { AMPLITUDE_API_KEY } from '@src/lib/constants/client';
import { global } from '@src/lib/styles/global';
import { pageViewTrackingEnrichment } from '@src/lib/utils/pageViewTrackingEnrichment';

export const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 0,
suspense: true,
refetchOnWindowFocus: false,
refetchOnMount: false,
refetchOnReconnect: false,
},
},
});

amplitude.add(pageViewTrackingEnrichment());
amplitude.init(AMPLITUDE_API_KEY, {
logLevel: amplitude.Types.LogLevel.Warn,
defaultTracking: true,
});

function MyApp({ Component, pageProps }: AppProps) {
const [queryClient] = useState(() => new QueryClient());

const router = useRouter();
useEffect(() => {
router.events.on('routeChangeComplete', gtm.pageview);
Expand Down Expand Up @@ -76,6 +86,7 @@ function MyApp({ Component, pageProps }: AppProps) {
<Global styles={global} />
<QueryClientProvider client={queryClient}>
<Component {...pageProps} />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
<GoogleTagManagerNoscript />
</>
Expand Down
2 changes: 1 addition & 1 deletion src/views/BlogPage/components/BlogPost/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export default function BlogPost({ selectedTap, blogPost }: BlogPostProps) {
<S.ThumbnailWrapper>
<S.Thumbnail
src={
blogPost.thumbnailUrl.charAt(0) !== 'h'
blogPost.thumbnailUrl?.charAt(0) !== 'h'
? `https:${blogPost.thumbnailUrl}`
: error
? img_blog_default
Expand Down
29 changes: 19 additions & 10 deletions src/views/ProjectPage/ProjectPage.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { css } from '@emotion/react';
import { useState } from 'react';
import { Suspense } from 'react';
import PageLayout from '@src/components/common/PageLayout';
import Select from '@src/components/common/Select';
import { useIsMobile } from '@src/hooks/useDevice';
import useStorage from '@src/hooks/useStorage';
import {
activeProjectCategoryList,
activeProjectPlatformList,
Expand All @@ -11,16 +11,21 @@ import {
} from '@src/lib/constants/project';
import { ProjectCategoryType, ProjectPlatformType } from '@src/lib/types/project';
import { ProjectList } from '@src/views/ProjectPage/components/project/ProjectList';
import ProjectListFallback from '@src/views/ProjectPage/components/project/ProjectListFallback';
import RecentProjectList from './components/RecentProjectList';
import useFetch from './hooks/useFetch';
import S from './styles';

function Projects() {
const [selectedCategory, setCategory] = useState<ProjectCategoryType>(ProjectCategoryType.ALL);
const [selectedPlatform, setPlatform] = useState<ProjectPlatformType>(ProjectPlatformType.ALL);

const state = useFetch(selectedCategory, selectedPlatform);
const isMobile = useIsMobile('899px');
const [selectedCategory, setCategory] = useStorage<ProjectCategoryType>(
'projectCategory',
'sessionStorage',
ProjectCategoryType.ALL,
);
const [selectedPlatform, setPlatform] = useStorage<ProjectPlatformType>(
'projectPlatform',
'sessionStorage',
ProjectPlatformType.ALL,
);

return (
<PageLayout
Expand All @@ -33,7 +38,9 @@ function Projects() {
<S.ContentWrapper>
<RecentProjectList />
<S.Spacing />
<S.SectionTitle>SOPT{!isMobile && '에서 진행된'} 프로젝트 둘러보기</S.SectionTitle>
<S.SectionTitle>
SOPT<span>에서 진행된</span> 프로젝트 둘러보기
</S.SectionTitle>
<S.FilterWrapper>
<Select
options={activeProjectCategoryList}
Expand All @@ -52,7 +59,9 @@ function Projects() {
baseValue={ProjectPlatformType.ALL}
/>
</S.FilterWrapper>
<ProjectList state={state} selectedCategory={selectedCategory} />
<Suspense fallback={<ProjectListFallback />}>
<ProjectList selectedCategory={selectedCategory} selectedPlatform={selectedPlatform} />
</Suspense>
</S.ContentWrapper>
</S.Root>
</PageLayout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ const GridWrapper = styled.div`
/* 모바일 뷰 */
@media (max-width: 899px) {
width: 325px;
grid-template-areas: 'img detail' 'footer footer';
grid-template-areas:
'img detail'
'footer footer';
grid-template-columns: 48px auto;
column-gap: 10px;
row-gap: 16px;
gap: 16px 10px;
padding: 16px;
}
`;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as S from './style';

interface CarouselProps {
itemWidth: number;
stride: number;
}

export default function RecentProjectListSkeletonUI({ itemWidth }: CarouselProps) {
const recentProjectListDummyArray = [1, 2, 3];

return (
<S.Wrapper>
<S.RightBlur />
<S.CarouselViewport>
<S.CarouselWrapper itemWidth={itemWidth} itemCount={3}>
{recentProjectListDummyArray.map((index) => (
<S.MarginWrapper key={index}>
<S.GridWrapper>
<S.ThumbnailImage />
<S.DetailWrapper>
<S.Title />
<S.Description />
</S.DetailWrapper>
<S.DetailFooterWrapper>
<S.Chip />
</S.DetailFooterWrapper>
</S.GridWrapper>
</S.MarginWrapper>
))}
</S.CarouselWrapper>
</S.CarouselViewport>
<S.RightArrow />
<S.DotWrapper>
{recentProjectListDummyArray.map((index) => (
<S.Dot key={index} />
))}
</S.DotWrapper>
</S.Wrapper>
);
}
Loading

0 comments on commit 74598ac

Please sign in to comment.