Skip to content

Commit

Permalink
Merge pull request #122 from kakao-tech-campus-2nd-step3/Weekly11
Browse files Browse the repository at this point in the history
Master<-Weekly11
  • Loading branch information
seung365 authored Nov 15, 2024
2 parents c1db0a4 + 78cd3d4 commit c2dd3cd
Show file tree
Hide file tree
Showing 19 changed files with 218 additions and 82 deletions.
1 change: 1 addition & 0 deletions src/apis/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const QUERY_KEYS = {
CHAT_ROOM: 'chatRoom',
PRODUCT_DETAIL: 'productDetail',
ARTIST_PROFILE: 'artistProfile',
WISH_LIST: 'wishList',
};

export default QUERY_KEYS;
40 changes: 40 additions & 0 deletions src/apis/users/useGetWishes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { APIResponse, SearchProductsResponse } from '@/types';
import { useSuspenseInfiniteQuery } from '@tanstack/react-query';
import fetchInstance from '../instance';
import QueryKeys from '../queryKeys';

async function getWishes({
pageParam = 0,
}: {
pageParam: number;
}): Promise<APIResponse<SearchProductsResponse>> {
const size = 20;
const response = await fetchInstance().get('/wishes', {
params: {
size,
page: pageParam,
},
});
return response.data;
}

const useGetWishes = () => {
const queryResult = useSuspenseInfiniteQuery<
APIResponse<SearchProductsResponse>,
Error,
APIResponse<SearchProductsResponse>,
[string],
number
>({
queryKey: [QueryKeys.WISH_LIST],
queryFn: ({ pageParam }) => getWishes({ pageParam }),
initialPageParam: 0,
getNextPageParam: (lastPage, allPages) => {
return lastPage.data.hasNext ? allPages.length : undefined;
},
});

return queryResult;
};

export default useGetWishes;
36 changes: 36 additions & 0 deletions src/components/common/Loader/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import styled from '@emotion/styled';

const LoaderWrapper = styled.div`
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
`;

const Spinner = styled.div`
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 1.5s linear infinite;
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
`;

const Loader = () => {
return (
<LoaderWrapper>
<Spinner />
</LoaderWrapper>
);
};

export default Loader;
3 changes: 2 additions & 1 deletion src/pages/Discover/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Suspense, useEffect } from 'react';
import { ErrorBoundary } from 'react-error-boundary';

import useGetFeed, { type Product } from '@/apis/products/useGetFeed';
import Loader from '@/components/common/Loader';
import SearchBar from '@/components/layouts/SearchBar';
import { HEIGHTS } from '@/styles/constants';

Expand All @@ -12,7 +13,7 @@ const Discover = () => (
<ContentWrapper>
{/* todo: 폴백 UI 만들기 */}
<ErrorBoundary fallback={<>Error</>}>
<Suspense fallback={<>Loading...</>}>
<Suspense fallback={<Loader />}>
<Feed />
</Suspense>
</ErrorBoundary>
Expand Down
3 changes: 2 additions & 1 deletion src/pages/My/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ErrorBoundary } from 'react-error-boundary';

import useGetArtist from '@/apis/artists/useGetArtist';
import useGetUser from '@/apis/users/useGetUser';
import Loader from '@/components/common/Loader';
import Footer from '@/components/layouts/Footer';
import useModeStore from '@/store/useModeStore';
import { HEIGHTS } from '@/styles/constants';
Expand All @@ -15,7 +16,7 @@ import UserProfileBox from './components/UserProfileBox';
const My = () => {
return (
<ErrorBoundary fallback={<div>Error...</div>}>
<Suspense fallback={<div>Loading...</div>}>
<Suspense fallback={<Loader />}>
<MyContent />
</Suspense>
</ErrorBoundary>
Expand Down
37 changes: 30 additions & 7 deletions src/pages/MyFavorites/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ import styled from '@emotion/styled';
import { useEffect, useState } from 'react';

import useGetFollow from '@/apis/users/useGetFollow';
import useGetWishList from '@/apis/users/useGetWishes';
import ArtistItem from '@/components/common/ArtistItem';
import CategoryTabBar from '@/components/common/CategoryTabBar';
import Loader from '@/components/common/Loader';
import ProductItem from '@/components/common/ProductItem';
import * as G from '@/styles/globalStyles';
import { User } from '@/types';
import { SearchProductInfo, User } from '@/types';

const MyFavorites = () => {
const categoryList = ['작품', '작가'];
const [selectedTab, setSelectedTab] = useState('작품');
const { data, status, refetch } = useGetFollow();
const { data: artistResults, status, refetch } = useGetFollow();
const { data: wishListResults } = useGetWishList();

useEffect(() => {
if (selectedTab === '작가') {
Expand All @@ -19,27 +23,46 @@ const MyFavorites = () => {
}, [selectedTab, refetch]);

if (status === 'pending') {
return <p>Loading...</p>;
return <Loader />;
}
if (status === 'error' || !data) {
if (status === 'error' || !artistResults) {
return <p>Error... console.log('Error:', error);</p>;
}

const handleTabClick = (tab: string) => {
setSelectedTab(tab);
};

return (
<>
<CategoryTabBar tabList={categoryList} tabClick={handleTabClick} tabState={selectedTab} />
{selectedTab === '작품' ? (
<Wrapper>작품</Wrapper> // 현재 이부분 api가 없어 비워두었습니다.
<Wrapper>
{wishListResults.data.products.length === 0 ? (
<p>찜한 작품이 없습니다.</p>
) : (
<G.Grid col={2}>
{wishListResults.data.products.map((product: SearchProductInfo) => (
<ProductItem
key={product.id}
id={product.id}
title={product.name}
author={product.artist}
price={product.price}
src={product.thumbnailUrl}
isLiked={true}
/>
))}
</G.Grid>
)}
</Wrapper>
) : (
<Wrapper>
{data?.data.content?.length === 0 ? (
{artistResults?.data.content?.length === 0 ? (
<p>팔로우한 작가가 없습니다.</p>
) : (
<G.Grid col={2}>
{data?.data.content?.map((artist: User) => (
{artistResults?.data.content?.map((artist: User) => (
<ArtistItem
artistId={artist.userId}
key={artist.userId}
Expand Down
3 changes: 2 additions & 1 deletion src/pages/ProductDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import usePostChatRoom from '@/apis/chats/usePostChatRoom';
import useGetDetail from '@/apis/products/useGetDetail';
import CTA, { CTAContainer } from '@/components/common/CTA';
import IconButton from '@/components/common/IconButton';
import Loader from '@/components/common/Loader';
import Header from '@/components/layouts/Header';
import { RouterPath } from '@/routes/path';
import useUserStore from '@/store/useUserStore';
Expand Down Expand Up @@ -75,7 +76,7 @@ const ProductDetailsContext = () => {
const ProductDetails = () => {
return (
<ErrorBoundary fallback={<div>Error Status</div>}>
<Suspense fallback={<div>Loading Status</div>}>
<Suspense fallback={<Loader />}>
<ProductDetailsContext />
</Suspense>
</ErrorBoundary>
Expand Down
40 changes: 27 additions & 13 deletions src/pages/SearchResults/components/ArtWorkContents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,23 @@ const ArtWorkContents = ({ searchWork }: { searchWork: SearchProductInfo[] }) =>
handleSelect={handleSelect}
/>
</ResultWrapper>
<G.Grid col={2}>
{sortedWork.map((item) => (
<ProductItem
id={item.id}
key={item.id}
author={item.artist}
title={item.name}
src={item.thumbnailUrl}
price={item.price}
isLiked={false}
/>
))}
</G.Grid>
{searchWorkLen === 0 ? (
<NoDataMessage>데이터가 없습니다.</NoDataMessage>
) : (
<G.Grid col={2}>
{sortedWork.map((item) => (
<ProductItem
id={item.id}
key={item.id}
author={item.artist}
title={item.name}
src={item.thumbnailUrl}
price={item.price}
isLiked={false}
/>
))}
</G.Grid>
)}
</div>
);
};
Expand All @@ -83,3 +87,13 @@ const ResultWrapper = styled.div`
align-items: center;
width: 100%;
`;

const NoDataMessage = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
padding: 40px 0;
font-weight: 600;
color: var(--color-black);
`;
40 changes: 27 additions & 13 deletions src/pages/SearchResults/components/ArtistContents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,23 @@ const ArtistContents = ({ searchArtist }: { searchArtist: SearchArtistInfo[] })
handleSelect={handleSelect}
/>
</ResultWrapper>
<G.Grid col={2}>
{sortedArtist.map((item) => (
<ArtistItem
artistId={item.id}
author={item.nickname}
src={item.artistImageUrl}
like={item.totalLikes}
follower={item.totalFollowers}
key={item.id}
isFollow={item.isFollowing}
/>
))}
</G.Grid>
{searchArtistLen === 0 ? (
<NoDataMessage>데이터가 없습니다.</NoDataMessage>
) : (
<G.Grid col={2}>
{sortedArtist.map((item) => (
<ArtistItem
artistId={item.id}
author={item.nickname}
src={item.artistImageUrl}
like={item.totalLikes}
follower={item.totalFollowers}
key={item.id}
isFollow={item.isFollowing}
/>
))}
</G.Grid>
)}
</div>
);
};
Expand All @@ -89,3 +93,13 @@ const ResultWrapper = styled.div`
align-items: center;
width: 100%;
`;

const NoDataMessage = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
padding: 40px 0;
font-weight: 600;
color: var(--color-black);
`;
37 changes: 28 additions & 9 deletions src/pages/SearchResults/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useNavigate, useSearchParams } from 'react-router-dom';
import useSearchArtists from '@/apis/search/useSearchArtists';
import useSearchProducts from '@/apis/search/useSearchProducts';
import CategoryTabBar from '@/components/common/CategoryTabBar';
import Loader from '@/components/common/Loader';
import SearchBar from '@/components/layouts/SearchBar';
import { RouterPath } from '@/routes/path';
import * as G from '@/styles/globalStyles';
Expand Down Expand Up @@ -56,20 +57,28 @@ const SearchResultsContent = () => {
<SubTitleFont>
작품 <ResultLightFont>({searchProductLen})</ResultLightFont>
</SubTitleFont>
<HorizontalWRapper>
<HorizontalFrame children={productsData} />
<MoreButton onClick={() => handleTabClick('작품')}> 더보기 </MoreButton>
</HorizontalWRapper>
{searchProductLen === 0 ? (
<NoDataMessage>데이터가 없습니다.</NoDataMessage>
) : (
<HorizontalWRapper>
<HorizontalFrame children={productsData} />
<MoreButton onClick={() => handleTabClick('작품')}> 더보기 </MoreButton>
</HorizontalWRapper>
)}
</Section>
<G.Gap height={12} />
<Section>
<SubTitleFont>
작가 <ResultLightFont>({searchArtistLen})</ResultLightFont>
</SubTitleFont>
<HorizontalWRapper>
<HorizontalFrame children={artistsData} />
<MoreButton onClick={() => handleTabClick('작가')}> 더보기 </MoreButton>
</HorizontalWRapper>
{searchArtistLen === 0 ? (
<NoDataMessage>데이터가 없습니다.</NoDataMessage>
) : (
<HorizontalWRapper>
<HorizontalFrame children={artistsData} />
<MoreButton onClick={() => handleTabClick('작가')}> 더보기 </MoreButton>
</HorizontalWRapper>
)}
</Section>
</AllContentWrapper>
)}
Expand All @@ -83,7 +92,7 @@ const SearchResultsContent = () => {
const SearchResults = () => {
return (
<ErrorBoundary fallback={<div>Error Status</div>}>
<Suspense fallback={<div>Loading Status</div>}>
<Suspense fallback={<Loader />}>
<SearchResultsContent />
</Suspense>
</ErrorBoundary>
Expand Down Expand Up @@ -149,3 +158,13 @@ const HorizontalWRapper = styled.div`
justify-content: center;
align-items: center;
`;

const NoDataMessage = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
padding: 20px 0;
font-weight: 600;
color: var(--color-black);
`;
2 changes: 1 addition & 1 deletion src/pages/chats/ChatList/components/ChatItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import styled from '@emotion/styled';
import { useNavigate } from 'react-router-dom';

import ProfileImage from '@/components/common/ProfileImage';
import { formatDate } from '@/utils';
import { formatDate } from '@/utils/dates';

type ChatItemProps = {
chatRoomId: number;
Expand Down
2 changes: 1 addition & 1 deletion src/pages/chats/ChatRoom/components/ChatInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import CancelIcon from '@/assets/icons/cancel-default.svg?react';
import ImageIcon from '@/assets/icons/image.svg?react';
import SendIcon from '@/assets/icons/send.svg?react';
import type { User } from '@/types/chats';
import { countNonSpaceChars } from '@/utils';
import { countNonSpaceChars } from '@/utils/strings';

type ChatInputProps = {
client: CompatClient | null;
Expand Down
Loading

0 comments on commit c2dd3cd

Please sign in to comment.