Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] - 여행기 및 여행 계획 수정 페이지 구현 #348

Merged
merged 44 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
8fefb47
refactor(ModalBottomSheet): 수정페이지에서도 사용하도록 props 유연하게 수정
simorimi Aug 14, 2024
76bf414
feat(route): 수정 페이지 route 추가
simorimi Aug 14, 2024
85f954a
refactor(RegisterPage): modalBottomSheet props 수정에 따른 리팩토링
simorimi Aug 14, 2024
6035c12
feat(DetailPage): 수정 버튼 활성화
simorimi Aug 14, 2024
b6805e7
feat(TravelogueEditPage): UI 구현
simorimi Aug 14, 2024
584b4f0
feat(TravelPlanEditPage): UI 구현
simorimi Aug 14, 2024
0b7cf97
Merge branch 'develop/fe' of https://github.com/woowacourse-teams/202…
simorimi Aug 18, 2024
cdc7ee0
refactor(errorMessage): only writer 속성명을 구체적으로 수정
simorimi Aug 18, 2024
12c03f3
refactor: state를 set 시키는 change 함수 구현 및 반환히도록 수정
simorimi Aug 18, 2024
48dd179
feat(TravelogueEditPage): 초기값 설정, 태그 ui 추가 및 타 사용자가 수정하지 못하도록 막는 기능 구현
simorimi Aug 18, 2024
c39671c
refactor(router): 오타 수정
simorimi Aug 19, 2024
6374bb5
refactor(BackDrop): position fixed로 수정
simorimi Aug 19, 2024
e3465f2
refactor(useTravelogueDays): change 함수명 수정
simorimi Aug 19, 2024
8875a83
refactor(TravelPlanRegisterPage): mutate 네이밍 수정
simorimi Aug 19, 2024
59749e0
feat(errorMessage): errorMessage 추가
simorimi Aug 19, 2024
396a32d
refactor(PlaceTodoListItem): value 값 및 isChecked 값 받도록 수정
simorimi Aug 19, 2024
cbf5339
feat(usePutTravelogue): 기능 구현
simorimi Aug 19, 2024
bea704d
feat(usePutTravelPlan): 기능 구현
simorimi Aug 19, 2024
d551183
feat(useTravelPlanDays): onChange 함수 추가
simorimi Aug 19, 2024
4846f46
feat(TravelPlanEditPage): 값 초기화, put 요청 및 에러 처리 기능 구현
simorimi Aug 19, 2024
9d447a8
refactor: useEffect 의존성 배열로 사용하여 useCallback으로 수정
simorimi Aug 19, 2024
d00027c
feat(debouncedTime): 상수화
simorimi Aug 19, 2024
220e336
refactor(extractId): 재사용성을 위한 수정
simorimi Aug 19, 2024
0459506
feat(extractUTCDate):UTC Date 추출 함수 유틸화
simorimi Aug 19, 2024
cf52695
refactor(travelPlan): days 타입 수정
simorimi Aug 19, 2024
ac7c0c9
refactor: 불 필요한 css 제거 및 일관성을 위한 수정
simorimi Aug 19, 2024
d09416f
refactor: 명세 isChecked와 checked 불일치로 인한 수정
simorimi Aug 19, 2024
b349353
refactor(TravelogueDetailPage): extractId 적용
simorimi Aug 19, 2024
7dceece
refactor: mutate 네이밍, 상수화, 유틸함수, Text 컴포넌트 적용
simorimi Aug 19, 2024
3b535f2
Merge branch 'develop/fe' of https://github.com/woowacourse-teams/202…
simorimi Aug 19, 2024
2a701e7
refactor(SearchFallback): 가운데로 오도록 정렬
simorimi Aug 19, 2024
c84564a
refactor(SearchFallback): common으로 분리
simorimi Aug 19, 2024
a6d489a
feat(MainPage): 태그 필터링 결과 없을 시 SearchFallback 보여주도록 구현
simorimi Aug 19, 2024
74d939f
refactor(MainPage): 태그 갯수 설정에 관한 설명 추가
simorimi Aug 20, 2024
5b4ca36
refactor(extractId): 네이밍 수정
simorimi Aug 20, 2024
b09fb25
refactor: extractID 네이밍 수정
simorimi Aug 20, 2024
8a95c92
refactor(extractId): extractLastPath 유틸화에 따른 분리
simorimi Aug 20, 2024
ed5b0dc
fix(ModalBottomSheet): 에니메이션 되지 않는 문제 해결
simorimi Aug 20, 2024
06d4297
refactor(SearchFallback): ui 위치 수정
simorimi Aug 20, 2024
782f714
refactor(TravelogueTabContent): negative margin-top 추가
simorimi Aug 20, 2024
0835878
refactor(TravelPlanRegisterPage): 여행 계획 등록 subText 추가
simorimi Aug 20, 2024
bab20ea
refactor(TravelogueDetailPage): 개행 추가
simorimi Aug 20, 2024
b520873
Merge branch 'develop/fe' of https://github.com/woowacourse-teams/202…
simorimi Aug 20, 2024
b20cdb4
refactor(TravelogueRegisterPage): mutate 네이밍 수정
simorimi Aug 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { Input } from "@components/common/Input/Input.styled";

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

import { extractLastPath } from "@utils/extractId";

import Header from "../Header";
import * as S from "./SearchHeader.styled";

Expand All @@ -21,7 +23,7 @@ const SearchHeader = () => {

const encodedKeyword =
location.pathname.split("/").length > MIN_KEYWORD_LENGTH
? location.pathname.split("/").pop()
? extractLastPath(location.pathname)
: "";

const receivedKeyword = encodedKeyword ? decodeURIComponent(encodedKeyword) : "";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import styled from "@emotion/styled";

export const BackDrop = styled.div`
position: absolute;
position: fixed;
inset: 0;
z-index: ${({ theme }) => theme.zIndex.overlay};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export const Default: Story = {
args: {
mainText: "여행기를 등록할까요?",
subText: "등록한 후에도 다시 여행기를 수정할 수 있어요.",
secondaryButtonLabel: "취소",
primaryButtonLabel: "확인",
isOpen: true,
onClose: () => {},
onConfirm: () => {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export interface ModalBottomSheetProps {
mainText: string;
subText: string;
isOpen: boolean;
primaryButtonLabel: string;
secondaryButtonLabel: string;
onClose: () => void;
onConfirm: () => void;
}
Expand All @@ -19,6 +21,8 @@ const ModalBottomSheet = ({
mainText,
subText,
isOpen,
primaryButtonLabel,
secondaryButtonLabel,
onClose,
onConfirm,
}: ModalBottomSheetProps) => {
Expand All @@ -32,10 +36,10 @@ const ModalBottomSheet = ({
<Content mainText={mainText} subText={subText} />
<Footer>
<Button variants="secondary" onClick={onClose}>
취소
{secondaryButtonLabel}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추상화 좋습니다!! 👍👍 isOpen 없앤 것도 좋구여!

</Button>
<Button variants="primary" onClick={onConfirm}>
확인
{primaryButtonLabel}
</Button>
</Footer>
</Container>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import styled from "@emotion/styled";

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

export const Layout = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: calc(100vh - 6rem);
gap: ${({ theme }) => theme.spacing.l};
gap: ${SPACING.l};
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

width: 100%;
`;

export const TextContainer = styled.div`
display: flex;
flex-direction: column;
align-items: center;
gap: ${({ theme }) => theme.spacing.m};
gap: ${SPACING.m};
`;
2 changes: 2 additions & 0 deletions frontend/src/components/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ export { default as Modal } from "./Modal/Modal";
export * from "./Header/index";
export { default as Checkbox } from "./Checkbox/Checkbox";
export { default as Chip } from "./Chip/Chip";
export { default as SearchFallback } from "./SearchFallback/SearchFallback";
export { default as FloatingButton } from "./FloatingButton/FloatingButton";
6 changes: 3 additions & 3 deletions frontend/src/components/layout/AppLayout/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { DefaultHeader, HomePageHeader, SearchHeader } from "@components/common"

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

import { extractLastPath } from "@utils/extractId";

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

const MIN_KEYWORD_LENGTH = 2;
Expand All @@ -13,9 +15,7 @@ const AppLayout = () => {
const pathName = location.pathname;

const encodedKeyword =
location.pathname.split("/").length > MIN_KEYWORD_LENGTH
? location.pathname.split("/").pop()
: "";
location.pathname.split("/").length > MIN_KEYWORD_LENGTH ? extractLastPath(pathName) : "";
const receivedKeyword = encodedKeyword ? decodeURIComponent(encodedKeyword) : "";

const getHeader = (pathName: string) => {
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/components/pages/main/MainPage.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const MainPageContentContainer = styled.div`

margin-top: ${SPACING.m};
padding: ${SPACING.m};
min-height: calc(100vh - 7.6rem);
`;

export const MainPageHeaderContainer = styled.div`
Expand All @@ -19,9 +20,16 @@ export const MainPageHeaderContainer = styled.div`
gap: ${SPACING.s};
`;

export const SearchFallbackWrapper = styled.div`
flex: 1;
position: relative;
`;

export const MainPageTraveloguesList = styled.ul`
display: flex;
flex: 1;
flex-direction: column;
justify-content: center;

gap: ${SPACING.m};
`;
Expand Down
45 changes: 27 additions & 18 deletions frontend/src/components/pages/main/MainPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import { css } from "@emotion/react";

import useInfiniteTravelogues from "@queries/useInfiniteTravelogues";

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

import { useDragScroll } from "@hooks/useDragScroll";
import useIntersectionObserver from "@hooks/useIntersectionObserver";
import useTagSelection from "@hooks/useTagSelection";

import { FORM_VALIDATIONS_MAP } from "@constants/formValidation";

import * as S from "./MainPage.styled";
import TravelogueCardSkeleton from "./TravelogueCard/skeleton/TravelogueCardSkeleton";

Expand All @@ -25,12 +26,14 @@ const MainPage = () => {

const { lastElementRef } = useIntersectionObserver(fetchNextPage);

const hasTravelogue = travelogues.length > 0;

return (
<S.MainPageContentContainer>
<S.MainPageHeaderContainer>
<Text textType="title">지금 뜨고 있는 여행기</Text>
<Text textType="detail" css={S.subTitleColorStyle}>
다른 이들의 여행을 한 번 구경해보세요.
{`다른 이들의 여행을 한 번 구경해보세요. (태그는 최대 ${FORM_VALIDATIONS_MAP.tags.maxCount}개까지 가능해요!)`}
</Text>
</S.MainPageHeaderContainer>

Expand Down Expand Up @@ -58,21 +61,27 @@ const MainPage = () => {
</S.MainPageTraveloguesList>
)}
<S.MainPageTraveloguesList>
{travelogues.map(
({ authorProfileUrl, authorNickname, id, title, thumbnail, likeCount, tags }) => (
<TravelogueCard
key={id}
travelogueOverview={{
authorProfileUrl,
id,
title,
thumbnail,
likeCount,
authorNickname,
tags,
}}
/>
),
{hasTravelogue ? (
travelogues.map(
({ authorProfileUrl, authorNickname, id, title, thumbnail, likeCount, tags }) => (
<TravelogueCard
key={id}
travelogueOverview={{
authorProfileUrl,
id,
title,
thumbnail,
likeCount,
authorNickname,
tags,
}}
/>
),
)
) : (
<S.SearchFallbackWrapper>
<SearchFallback title="휑" text="다른 태그를 선택해 주세요!" />
</S.SearchFallbackWrapper>
)}
</S.MainPageTraveloguesList>
<FloatingButton />
Expand Down
21 changes: 11 additions & 10 deletions frontend/src/components/pages/search/SearchPage.styled.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import styled from "@emotion/styled";

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

export const Layout = styled.div`
display: flex;
flex-direction: column;
padding: 1.6rem;
gap: ${SPACING.m};

gap: ${({ theme }) => theme.spacing.s};
margin-top: ${SPACING.m};
min-height: calc(100vh - 6rem);
padding: ${SPACING.m};
`;

h1 {
${({ theme }) => theme.typography.mobile.title};
}
export const SearchFallbackWrapper = styled.div`
flex: 1;
position: relative;
`;

export const MainPageTraveloguesList = styled.ul`
display: flex;
flex-direction: column;

gap: ${({ theme }) => theme.spacing.m};
`;

export const MainPageContentContainer = styled.div`
padding-top: 1.6rem;
gap: ${SPACING.m};
`;
28 changes: 21 additions & 7 deletions frontend/src/components/pages/search/SearchPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ import { css } from "@emotion/react";

import useInfiniteSearchTravelogues from "@queries/useInfiniteSearchTravelogues";

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

import useIntersectionObserver from "@hooks/useIntersectionObserver";

import { extractLastPath } from "@utils/extractId";

import TravelogueCardSkeleton from "../main/TravelogueCard/skeleton/TravelogueCardSkeleton";
import * as S from "./SearchPage.styled";
import SearchFallback from "./fallback/SearchFallback";

const SearchPage = () => {
const SKELETON_COUNT = 5;

const location = useLocation();
const encodedKeyword =
location.pathname.split("/").length > 2 ? location.pathname.split("/").pop() : "";
location.pathname.split("/").length > 2 ? extractLastPath(location.pathname) : "";
const keyword = encodedKeyword ? decodeURIComponent(encodedKeyword) : "";

const { travelogues, status, fetchNextPage } = useInfiniteSearchTravelogues(keyword);
Expand All @@ -28,18 +28,32 @@ const SearchPage = () => {

if (!keyword) {
return (
<SearchFallback title="보고 싶은 여행기를 검색해주세요!" text="여행기 키워드를 입력해봐요!" />
<S.Layout>
<S.SearchFallbackWrapper>
<SearchFallback
title="보고 싶은 여행기를 검색해주세요!"
text="여행기 키워드를 입력해봐요!"
/>
</S.SearchFallbackWrapper>
</S.Layout>
);
}

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

return (
<S.Layout>
<FloatingButton />
<S.Layout>{keyword && <Text textType="title">{`"${keyword}" 검색 결과`}</Text>}</S.Layout>
{keyword && <Text textType="title">{`"${keyword}" 검색 결과`}</Text>}
{status === "pending" && (
<S.MainPageTraveloguesList>
{Array.from({ length: SKELETON_COUNT }, (_, index) => (
Expand Down
Loading
Loading