-
Notifications
You must be signed in to change notification settings - Fork 2
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
[민우] - 발자취 페이지 : 내 발자취 탭 구현 #495
Open
MinwooP
wants to merge
19
commits into
dev
Choose a base branch
from
feat/#492/my-footprints
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
adf2d67
♻️ : #492 - 발자취 페이지 파일 생성
MinwooP 7281ae2
✨ : #492 - 발자취 페이지 하위 컴포넌트 파일 및 state 생성
MinwooP 7b29439
✨ : #492 - 발자취 페이지 상단 탭 FootPrintTab 컴포넌트 기능 및 디자인 구현
MinwooP 454925d
✨ : #492 - FootPrintFilter 컴포넌트 기본 로직 구현
MinwooP ef5eeb5
✨ : #492 - 발자취 페이지 필터에 사용할 계획 List를 불러오는 useGetMyPlansForFootprintQue…
MinwooP 6efe877
✨ : #492 - FootPrintFilter 컴포넌트 내 useGetMyPlansForFootprintQuery 훅 사용…
MinwooP 5210f92
♻️ : #492 - Icon 컴포넌트 내 검색 아이콘 search 종류 추가
MinwooP 659b773
💄 : #492 - FootPrintFilter 컴포넌트 검색 버튼 CSS 구현
MinwooP e5527f6
💄 : #492 - Dropdown 컴포넌트 내 text 고정 width 및 말줄임표 설정
MinwooP f878dd7
♻️ : #492 - FOOTPRINT_PLAN 상수 정의 => 모든 계획, 계획 없음 data 상수화
MinwooP 3befbb9
✨ : #492 - FootPrintItem 컴포넌트 기본 로직 정의
MinwooP e71a5be
✨ : #492 - FootPrintItem dummy data 추가 및 css 작업
MinwooP 37638f0
💄 : #492 - FootPrintList 스크롤 위해 height 설정
MinwooP f7f4ea9
✨ : #492 - 발자취 조회 무한 스크롤 적용 위해 임시로 getAllPlans API 사용
MinwooP 2a67198
🐛 : #492 - npm react-intersection-observer 라이브러리 설치
MinwooP 44e6590
✨ : #492 - useInView hook를 사용해 발자취조회 무한 스크롤 구현
MinwooP d071d13
✨ : #492 - 계획 작성 날짜를 YYYY-MM-DD 형식으로 바꿔주는 changeCreateAtToDate hook 구현
MinwooP 75ebb5c
🐛 : #492 - merge origin dev
MinwooP 1053af7
♻️ : #492 - footprints 폴더명 url에 맞게 footprint로 변경
MinwooP File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { DOMAIN } from '@/constants/api'; | ||
import { | ||
GetAllPlansRequestQuery, | ||
GetAllPlansResponse, | ||
} from '@/types/apis/plan/GetAllPlans'; | ||
import { axiosInstanceClient } from '../axiosInstanceClient'; | ||
|
||
export const getMyFootPrints = async (query: GetAllPlansRequestQuery) => { | ||
const { data } = await axiosInstanceClient.get<GetAllPlansResponse>( | ||
DOMAIN.GET_PLANS_ALL, | ||
{ | ||
authorization: false, | ||
params: { | ||
...query, | ||
}, | ||
}, | ||
); | ||
return data; | ||
}; |
5 changes: 5 additions & 0 deletions
5
src/app/footprint/_Components/AllFootPrints/AllFootPrints.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import React from 'react'; | ||
|
||
export default function AllFootPrints() { | ||
return <div></div>; | ||
} |
Empty file.
87 changes: 87 additions & 0 deletions
87
src/app/footprint/_Components/FootPrintFilter/FootPrintFilter.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { Dropdown, Icon } from '@/components'; | ||
import { FOOTPRINT_PLAN } from '@/constants'; | ||
import { useGetMyPlansForFootprintQuery } from '@/hooks/apis'; | ||
import classNames from 'classnames'; | ||
import React, { useEffect, useMemo, useState } from 'react'; | ||
import { planType } from '../MyFootPrints/MyFootPrints'; | ||
import './index.scss'; | ||
|
||
interface FootPrintFilterProps { | ||
setYear: (year: number) => void; | ||
setPlan: (plan: planType) => void; | ||
} | ||
|
||
const yearOptions = [{ value: 2024, name: '2024년' }]; | ||
|
||
export default function FootPrintFilter({ | ||
setYear, | ||
setPlan, | ||
}: FootPrintFilterProps) { | ||
const [selectedYear, setSelectedYear] = useState(2024); | ||
const [selectedPlan, setSelectedPlan] = useState<planType>( | ||
FOOTPRINT_PLAN.ALL_PLAN, | ||
); | ||
|
||
const handleSelectedPlan = (newSelectedPlanId: number) => { | ||
const newSelectedPlan = planOptions.find( | ||
(plan) => plan.value === newSelectedPlanId, | ||
); | ||
setSelectedPlan({ | ||
planId: newSelectedPlan!.value, | ||
planTitle: newSelectedPlan!.name, | ||
}); | ||
}; | ||
|
||
const { yearPlans } = useGetMyPlansForFootprintQuery(selectedYear); | ||
|
||
const planOptions = useMemo(() => { | ||
// 서버로부터 받아온 yearPlans가 변경되지 않는 이상 변하지 않는 변수 | ||
return yearPlans.map((plan) => ({ | ||
value: plan.planId, | ||
name: plan.planTitle, | ||
})); | ||
}, [yearPlans]); | ||
|
||
useEffect(() => { | ||
// selectedYear이 바뀔 때마다, yearPlans의 값이 바뀔테니 | ||
// selectedPlan의 값은 "모든 계획"으로 변경해주기 | ||
setSelectedPlan(FOOTPRINT_PLAN.ALL_PLAN); | ||
}, [selectedYear]); | ||
|
||
const handleClickSearchBtn = () => { | ||
// 현재 dropdown에서 선택되어있는 year, plan 값으로 부모의 year, plan을 변경 | ||
if (selectedPlan.planId !== FOOTPRINT_PLAN.EMPTY.planId) { | ||
// "계획 없음"이 선택되지 않았을 때만 변경 가능하도록 | ||
setYear(selectedYear); | ||
setPlan(selectedPlan); | ||
} | ||
}; | ||
|
||
return ( | ||
<div className={classNames('footprint-filter')}> | ||
<Dropdown | ||
dropdownId="year-filter" | ||
options={yearOptions} | ||
selectedValue={selectedYear} | ||
setSelectedValue={(newSelectedYear: number) => { | ||
setSelectedYear(newSelectedYear); | ||
}} | ||
classNameList={['footprint-filter__dropdown--year']} | ||
/> | ||
|
||
<Dropdown | ||
dropdownId="plan-filter" | ||
options={planOptions} | ||
selectedValue={selectedPlan.planId} | ||
setSelectedValue={handleSelectedPlan} | ||
classNameList={['footprint-filter__dropdown--filter']} | ||
/> | ||
|
||
<button | ||
className={classNames('footprint-filter__search-btn')} | ||
onClick={handleClickSearchBtn}> | ||
<Icon name={'SEARCH'} color={'white-100'} size="lg" /> | ||
</button> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
.footprint-filter { | ||
display: flex; | ||
gap: 0.75rem; | ||
align-items: center; | ||
|
||
&__search-btn { | ||
&:hover { | ||
cursor: pointer; | ||
} | ||
display: flex; | ||
justify-content: center; | ||
padding: 0.25rem; | ||
align-items: center; | ||
border-radius: 10px; | ||
background-color: var(--origin-primary); | ||
} | ||
} |
67 changes: 67 additions & 0 deletions
67
src/app/footprint/_Components/FootPrintList/FootPrintList.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
'use client'; | ||
|
||
import { COLOR } from '@/constants'; | ||
import { useMyFootPrintsQuery } from '@/hooks/apis/useMyFootPrintsQuery'; | ||
import classNames from 'classnames'; | ||
import React, { useEffect } from 'react'; | ||
import { useInView } from 'react-intersection-observer'; | ||
import { FadeLoader } from 'react-spinners'; | ||
import FootprintItem from '../FootprintItem/FootprintItem'; | ||
import { planType } from '../MyFootPrints/MyFootPrints'; | ||
import './index.scss'; | ||
|
||
interface FootPrintListProps { | ||
year: number; | ||
plan: planType; | ||
} | ||
|
||
export default function FootPrintList({ year, plan }: FootPrintListProps) { | ||
// TODO: prop으로 받은 year과 plan에 해당하는 발자취 list들을 서버로부터 받아온다. | ||
// - plan.planId === -1 => 모든 계획일 것 | ||
// - plan.planId === -2 => 해당 year에 해당하는 계획이 없는 것 | ||
console.log(`${year}과 ${plan}에 해당하는 발자취 List로 변경 필요`); | ||
|
||
const { tempFootPrintList, fetchNextPage, isFetchingNextPage } = | ||
useMyFootPrintsQuery({ | ||
sort: 'latest', | ||
current: true, | ||
}); | ||
|
||
const { ref, inView } = useInView(); | ||
|
||
useEffect(() => { | ||
// ref로 참조하고 있는 div 요소가 viewPort에 보여진다면 다음 페이지 fetch | ||
if (inView) { | ||
fetchNextPage(); | ||
} | ||
}, [inView]); | ||
|
||
return ( | ||
<ul className={classNames('footprint-list')}> | ||
{tempFootPrintList.map((item) => { | ||
return ( | ||
<FootprintItem | ||
key={item.id} | ||
id={item.id} | ||
iconNumber={item.iconNumber} | ||
title={item.title} | ||
createdAt={item.createdAt} | ||
ajajas={item.ajajas} | ||
tags={item.tags} | ||
/> | ||
); | ||
})} | ||
|
||
<div className="footprint-list__loading-wrapper"> | ||
{isFetchingNextPage ? ( | ||
<FadeLoader color={COLOR.PRIMARY} speedMultiplier={1.3} /> | ||
) : ( | ||
<div className="footprint-list__end" ref={ref} /> | ||
)} | ||
</div> | ||
</ul> | ||
|
||
// TODO: ${year}와 ${plan.planTitle}에 해당하는 FootPrintList 출력 | ||
// -> 지금은 임시로 "계획 전체조회 api(계획 둘러보기)"를 사용하고 있음 | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
.footprint-list { | ||
display: flex; | ||
flex-direction: column; | ||
gap: 1rem; | ||
overflow-y: scroll; | ||
|
||
&__loading-wrapper { | ||
display: flex; | ||
justify-content: center; | ||
} | ||
|
||
&__end { | ||
&:before { | ||
content: ''; | ||
display: block; | ||
height: 12px; | ||
} | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
src/app/footprint/_Components/FootPrintTab/FootPrintTab.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import classNames from 'classnames'; | ||
import React from 'react'; | ||
import './index.scss'; | ||
|
||
interface FootPrintTabProps { | ||
isMyFootPrintsTab: boolean; | ||
setMyFootPrintsTab: () => void; | ||
setAllFootPrintsTab: () => void; | ||
} | ||
|
||
const TAB_MENU = { | ||
MY: '내 발자취', | ||
ALL: '둘러보기', | ||
}; | ||
|
||
export default function FootPrintTab({ | ||
isMyFootPrintsTab, | ||
setMyFootPrintsTab, | ||
setAllFootPrintsTab, | ||
}: FootPrintTabProps) { | ||
const handleClickMyFootPrintsTab = () => { | ||
if (!isMyFootPrintsTab) { | ||
setMyFootPrintsTab(); | ||
} | ||
}; | ||
|
||
const handleClickAllFootPrintsTab = () => { | ||
if (isMyFootPrintsTab) { | ||
setAllFootPrintsTab(); | ||
} | ||
}; | ||
|
||
return ( | ||
<div className={classNames('footprint-tab')}> | ||
<div | ||
className={classNames( | ||
'footprint-tab__menu', | ||
'font-size-base', | ||
isMyFootPrintsTab | ||
? 'footprint-tab--focused' | ||
: 'footprint-tab--normal', | ||
)} | ||
onClick={handleClickMyFootPrintsTab}> | ||
{TAB_MENU.MY} | ||
<div | ||
className={classNames('footprint-tab__underline', { | ||
'footprint-tab__underline--focused': isMyFootPrintsTab, | ||
})} | ||
/> | ||
</div> | ||
<div | ||
className={classNames( | ||
'footprint-tab__menu', | ||
'font-size-base', | ||
!isMyFootPrintsTab | ||
? 'footprint-tab--focused' | ||
: 'footprint-tab--normal', | ||
)} | ||
onClick={handleClickAllFootPrintsTab}> | ||
{TAB_MENU.ALL} | ||
<div | ||
className={classNames('footprint-tab__underline', { | ||
'footprint-tab__underline--focused': !isMyFootPrintsTab, | ||
})} | ||
/> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
.footprint-tab { | ||
margin-top: 2rem; | ||
display: flex; | ||
gap: 0rem; | ||
&:hover { | ||
cursor: pointer; | ||
} | ||
|
||
&__menu { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
gap: 0.5rem; | ||
width: 6rem; | ||
} | ||
|
||
&__underline { | ||
background-color: var(--origin-secondary); | ||
height: 0.125rem; | ||
width: 100%; | ||
|
||
&--focused { | ||
background-color: var(--origin-primary); | ||
} | ||
} | ||
|
||
&--normal { | ||
color: var(--origin-secondary); | ||
} | ||
|
||
&--focused { | ||
color: var(--origin-primary); | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
둘러보기 페이지와 다르게 useInView 쓴 이유가 있을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아직 적용하지는 않았지만, useInView를 사용해 특정 element가 viewPort에 들어오는지 나가는지를 파악해, 스크롤이 많이 된다면 현재 viewPort에 보이지 않고 상단에 쌓여있는 element들은 dom에서 제거해주는 기능을 추가해주기 위해 사용했습니다!!
혜수님은 둘러보기 페이지에서 react-infinite-scroller 라이브러리를 사용하신 것 같은데 이 라이브러리로는 각 element의 viewPort 진입 여부를 각각 판단해주는 기능은 없는 것 같아서요!!