Skip to content

Commit

Permalink
Merge branch 'develop/fe' into feature/fe/#538
Browse files Browse the repository at this point in the history
  • Loading branch information
jinyoung234 committed Oct 23, 2024
2 parents 2f0a396 + 74c9dfb commit 860512c
Show file tree
Hide file tree
Showing 41 changed files with 836 additions and 103 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import React from "react";

import * as S from "./CharacterCount.styled";

interface CharacterCountProps {
interface CharacterCountProps extends React.ComponentPropsWithoutRef<"div"> {
count?: number;
maxCount?: number;
}

const CharacterCount = ({ count, maxCount }: CharacterCountProps) => {
const CharacterCount = ({ count, maxCount, ...props }: CharacterCountProps) => {
return (
<S.CharacterCountWrapper>
<S.CharacterCountWrapper {...props}>
{count && maxCount ? <S.CharacterCount>{`${count}/${maxCount}`}</S.CharacterCount> : null}
</S.CharacterCountWrapper>
);
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/common/Tab/Tab.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const TabItem = styled.li<{ isSelected: boolean; $tabCount: number }>`
justify-content: center;
align-items: center;
padding: ${({ theme }) => theme.spacing.s} ${({ theme }) => theme.spacing.l};
padding: ${({ theme }) => theme.spacing.s};
border-bottom: 2px solid
${({ isSelected, theme }) => (isSelected ? `${theme.colors.primary}` : "transparent")};
Expand Down
45 changes: 45 additions & 0 deletions frontend/src/components/pages/my/MyLikes/MyLikes.styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import styled from "@emotion/styled";

export const Layout = styled.div`
display: flex;
width: 100%;
height: 100%;
gap: ${(props) => props.theme.spacing.m};
`;

export const List = styled.ul`
display: flex;
flex-direction: column;
gap: ${(props) => props.theme.spacing.m};
width: 100%;
padding: 0 ${(props) => props.theme.spacing.l};
`;

export const Container = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: ${(props) => props.theme.spacing.s};
`;

export const DetailContainer = styled.div`
display: flex;
align-items: center;
gap: ${(props) => props.theme.spacing.m};
width: 100%;
`;

export const BoxButton = styled.button`
display: flex;
gap: ${(props) => props.theme.spacing.m};
justify-content: flex-start;
align-items: center;
width: 100%;
padding: ${(props) => props.theme.spacing.m};
border: 1px solid ${(props) => props.theme.colors.border};
border-radius: 10px;
`;
102 changes: 102 additions & 0 deletions frontend/src/components/pages/my/MyLikes/MyLikes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";

import { css } from "@emotion/react";

import type { UserResponse } from "@type/domain/user";

import useInfiniteMyLikes from "@queries/useInfiniteMyLikes";

import { AvatarCircle, Text } from "@components/common";
import MyPageTabContentSkeleton from "@components/pages/my/MyPageTabContentSkeleton/MyPageTabContentSkeleton";

import useIntersectionObserver from "@hooks/useIntersectionObserver";

import { ERROR_MESSAGE_MAP } from "@constants/errorMessage";
import { ROUTE_PATHS_MAP } from "@constants/route";

import theme from "@styles/theme";

import MyPageTabContent from "../MyPageTabContent/MyPageTabContent";
import * as S from "./MyLikes.styled";

interface MyLikesProps {
userData: UserResponse;
}

const MyLikes = ({ userData }: MyLikesProps) => {
const { myLikes, fetchNextPage, status, isPaused, error } = useInfiniteMyLikes(userData);
const { lastElementRef } = useIntersectionObserver(fetchNextPage);

const navigate = useNavigate();

const handleClickTravelogue = (id: string) => {
navigate(ROUTE_PATHS_MAP.travelogue(Number(id)));
};

const handleClickIconButton = () => {
navigate(ROUTE_PATHS_MAP.root);
};

useEffect(() => {
if (isPaused) alert(ERROR_MESSAGE_MAP.network);
}, [isPaused]);

if (status === "pending") return <MyPageTabContentSkeleton />;

if (error) alert(error.message);

return (
<>
<MyPageTabContent
iconButtonType="search-icon"
iconButtonLabel="다른 여행기 구경하기"
onClickIconButton={handleClickIconButton}
contentDetail={myLikes}
renderItem={({ id, title, createdAt, thumbnailUrl, authorName }) => (
<S.Layout onClick={() => handleClickTravelogue(id)}>
<AvatarCircle size="medium" profileImageUrl={thumbnailUrl} />

<S.Container>
<Text
textType="body"
css={css`
font-weight: 500;
`}
>
{title}
</Text>
<S.DetailContainer>
<Text
textType="detail"
css={css`
color: ${theme.colors.text.secondary};
`}
>
{authorName}
</Text>
<Text
textType="detail"
css={css`
color: ${theme.colors.text.secondary};
`}
>
{createdAt}
</Text>
</S.DetailContainer>
</S.Container>
</S.Layout>
)}
/>

<div
ref={lastElementRef}
css={css`
height: 1px;
`}
/>
</>
);
};

export default MyLikes;
3 changes: 2 additions & 1 deletion frontend/src/components/pages/my/MyPage.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const Layout = styled.div`
gap: ${(props) => props.theme.spacing.xl};
width: 100%;
padding: ${(props) => props.theme.spacing.l};
padding: ${(props) => props.theme.spacing.l} 0;
`;

export const TabContentContainer = styled.div`
Expand All @@ -34,6 +34,7 @@ export const ProfileContainer = styled.div`
gap: ${({ theme }) => theme.spacing.m};
width: 100%;
padding: 0 ${(props) => props.theme.spacing.l};
`;

export const ProfileEditButtonContainer = styled.div`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ export const Container = styled.div`
export const List = styled.ul`
display: flex;
flex-direction: column;
width: 100%;
gap: ${(props) => props.theme.spacing.m};
width: 100%;
padding: 0 ${(props) => props.theme.spacing.l};
`;

export const ColorButtonStyle = css`
Expand All @@ -37,6 +39,7 @@ export const BoxButton = styled.button`
gap: ${(props) => props.theme.spacing.m};
justify-content: flex-start;
align-items: center;
width: 100%;
padding: ${(props) => props.theme.spacing.m};
border: 1px solid ${(props) => props.theme.colors.border};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { css } from "@emotion/react";

import { IconButton } from "@components/common";
import SVG_ICONS_MAP from "@components/common/Icon/svg-icons.json";

import { SEMANTIC_COLORS } from "@styles/tokens";

Expand All @@ -9,10 +10,12 @@ import * as S from "./MyPageTabContent.styled";
const ICON_BUTTON_TEXT = {
ADD_TRAVEL_PLAN: "새 여행 계획 추가하기",
ADD_TRAVELOGUE: "새 여행기 추가하기",
GO_ROOT_PAGE: "다른 여행기 구경하기",
} as const;

interface MyPageTabContentProps<T extends { id: string }> {
iconButtonLabel: (typeof ICON_BUTTON_TEXT)[keyof typeof ICON_BUTTON_TEXT];
iconButtonType?: keyof typeof SVG_ICONS_MAP;
onClickIconButton: () => void;
contentDetail: T[];
renderItem: (item: T) => React.ReactNode;
Expand All @@ -21,6 +24,7 @@ interface MyPageTabContentProps<T extends { id: string }> {
const MyPageTabContent = <T extends { id: string }>({
contentDetail,
iconButtonLabel,
iconButtonType = "plus",
onClickIconButton,
renderItem,
}: React.PropsWithChildren<MyPageTabContentProps<T>>) => {
Expand All @@ -29,7 +33,7 @@ const MyPageTabContent = <T extends { id: string }>({
<IconButton
size="16"
position="left"
iconType="plus"
iconType={iconButtonType}
color={SEMANTIC_COLORS.primary}
css={[
S.ColorButtonStyle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,3 @@ export const Container = styled.div`
align-items: flex-start;
gap: ${(props) => props.theme.spacing.s};
`;

export const TraveloguesList = styled.ul`
display: flex;
flex-direction: column;
width: 100%;
gap: ${(props) => props.theme.spacing.m};
`;
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const MyTravelogues = ({ userData }: MyTraveloguesProps) => {
color: ${theme.colors.text.secondary};
`}
>
게시일 {createdAt}
{createdAt}
</Text>
</S.Container>
</S.Layout>
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/pages/my/constants.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { ERROR_MESSAGE_MAP } from "@constants/errorMessage";

import MyLikes from "./MyLikes/MyLikes";
import MyTravelPlans from "./MyTravelPlans/MyTravelPlans";
import MyTravelogues from "./MyTravelogues/MyTravelogues";

export const TAB_CONTENT = [
{ label: "✈️ 내 여행 계획", component: MyTravelPlans },
{ label: "📝 내 여행기", component: MyTravelogues },
{ label: "❤️ 좋아요", component: MyLikes },
] as const;

export const IGNORED_ERROR_MESSAGES = [ERROR_MESSAGE_MAP.api.login, "Network Error"];
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { SearchFallback, Text } from "@components/common";

import * as S from "./TravelogueList.styled";

interface EmptySearchResultProps {
keyword: string | undefined;
}

const EmptySearchResult = ({ keyword }: EmptySearchResultProps) => {
return (
<S.Layout>
{keyword && (
<Text css={S.searchResultTextStyle} textType="title">{`"${keyword}" 검색 결과`}</Text>
)}
<S.SearchFallbackWrapper>
<SearchFallback title="휑" text="검색 결과가 없어요." />
</S.SearchFallbackWrapper>
</S.Layout>
);
};

export default EmptySearchResult;
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import type { SearchType } from "@type/domain/travelogue";

import useInfiniteSearchTravelogues from "@queries/useInfiniteSearchTravelogues";

import { SearchFallback, Text } from "@components/common";
import { Text } from "@components/common";
import TravelogueCard from "@components/pages/main/TravelogueCard/TravelogueCard";
import TravelogueCardSkeleton from "@components/pages/main/TravelogueCard/skeleton/TravelogueCardSkeleton";

import useIntersectionObserver from "@hooks/useIntersectionObserver";

import { ERROR_MESSAGE_MAP } from "@constants/errorMessage";

import EmptySearchResult from "./EmptySearchResult";
import * as S from "./TravelogueList.styled";

const SKELETON_COUNT = 5;
Expand All @@ -29,22 +30,13 @@ const TravelogueList = ({ keyword, searchType }: TravelogueListProps) => {
const { lastElementRef } = useIntersectionObserver(fetchNextPage);

if (travelogues.length === 0 && status === "success") {
return (
<S.Layout>
{keyword && (
<Text css={S.searchResultTextStyle} textType="title">{`"${keyword}" 검색 결과`}</Text>
)}
<S.SearchFallbackWrapper>
<SearchFallback title="휑" text="검색 결과가 없어요." />
</S.SearchFallbackWrapper>
</S.Layout>
);
return <EmptySearchResult keyword={keyword} />;
}

if (status === "error") {
error && alert(error.message);

return <SearchFallback title="휑" text="검색 결과가 없어요." />;
return <EmptySearchResult keyword={keyword} />;
}

if (isPaused) alert(ERROR_MESSAGE_MAP.network);
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/pages/search/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const TAB_CONTENT = [
{ label: "제목", searchType: "TITLE" },
{ label: "작성자", searchType: "AUTHOR" },
{ label: "나라", searchType: "COUNTRY" },
] as const;
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ export const PageInfoContainer = styled.div`
gap: ${({ theme }) => theme.spacing.s};
`;

export const TitleMessageContainer = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
`;

export const StartDateContainer = styled.div`
display: flex;
flex-direction: column;
Expand All @@ -46,3 +52,14 @@ export const addButtonStyle = css`
border: 1px solid ${theme.colors.border};
border-radius: ${SPACING.s};
`;

export const errorTextStyle = css`
flex: 2;
width: 100%;
color: ${theme.colors.danger};
`;

export const characterCountStyle = css`
flex: 1;
`;
Loading

0 comments on commit 860512c

Please sign in to comment.