diff --git a/package-lock.json b/package-lock.json index 1d7044cd..c1e3a7de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "react-form-stepper": "^2.0.3", "react-hot-toast": "^2.4.1", "react-infinite-scroller": "^1.2.6", + "react-intersection-observer": "^9.8.2", "react-spinners": "^0.13.8", "recoil": "^0.7.7" }, @@ -4832,6 +4833,20 @@ "react": "^0.14.9 || ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-intersection-observer": { + "version": "9.8.2", + "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.8.2.tgz", + "integrity": "sha512-901naEiiZmse3p+AmtbQ3NL9xx+gQ8TXLiGDc+8GiE3JKJkNV3vP737aGuWTAXBA+1QqxPrDDE+fIEgYpGDlrQ==", + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/package.json b/package.json index 2970ddec..67c1357d 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "react-form-stepper": "^2.0.3", "react-hot-toast": "^2.4.1", "react-infinite-scroller": "^1.2.6", + "react-intersection-observer": "^9.8.2", "react-spinners": "^0.13.8", "recoil": "^0.7.7" }, diff --git a/src/apis/client/getMyFootPrints.ts b/src/apis/client/getMyFootPrints.ts new file mode 100644 index 00000000..e26b0574 --- /dev/null +++ b/src/apis/client/getMyFootPrints.ts @@ -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( + DOMAIN.GET_PLANS_ALL, + { + authorization: false, + params: { + ...query, + }, + }, + ); + return data; +}; diff --git a/src/app/footprint/_Components/AllFootPrints/AllFootPrints.tsx b/src/app/footprint/_Components/AllFootPrints/AllFootPrints.tsx new file mode 100644 index 00000000..b5cc0fee --- /dev/null +++ b/src/app/footprint/_Components/AllFootPrints/AllFootPrints.tsx @@ -0,0 +1,5 @@ +import React from 'react'; + +export default function AllFootPrints() { + return
; +} diff --git a/src/app/footprint/_Components/AllFootPrints/index.scss b/src/app/footprint/_Components/AllFootPrints/index.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/footprint/_Components/FootPrintFilter/FootPrintFilter.tsx b/src/app/footprint/_Components/FootPrintFilter/FootPrintFilter.tsx new file mode 100644 index 00000000..2771cdd4 --- /dev/null +++ b/src/app/footprint/_Components/FootPrintFilter/FootPrintFilter.tsx @@ -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( + 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 ( +
+ { + setSelectedYear(newSelectedYear); + }} + classNameList={['footprint-filter__dropdown--year']} + /> + + + + +
+ ); +} diff --git a/src/app/footprint/_Components/FootPrintFilter/index.scss b/src/app/footprint/_Components/FootPrintFilter/index.scss new file mode 100644 index 00000000..e1d8d3b6 --- /dev/null +++ b/src/app/footprint/_Components/FootPrintFilter/index.scss @@ -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); + } +} diff --git a/src/app/footprint/_Components/FootPrintList/FootPrintList.tsx b/src/app/footprint/_Components/FootPrintList/FootPrintList.tsx new file mode 100644 index 00000000..aa7b9b25 --- /dev/null +++ b/src/app/footprint/_Components/FootPrintList/FootPrintList.tsx @@ -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 ( + + + // TODO: ${year}와 ${plan.planTitle}에 해당하는 FootPrintList 출력 + // -> 지금은 임시로 "계획 전체조회 api(계획 둘러보기)"를 사용하고 있음 + ); +} diff --git a/src/app/footprint/_Components/FootPrintList/index.scss b/src/app/footprint/_Components/FootPrintList/index.scss new file mode 100644 index 00000000..c113e6fb --- /dev/null +++ b/src/app/footprint/_Components/FootPrintList/index.scss @@ -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; + } + } +} diff --git a/src/app/footprint/_Components/FootPrintTab/FootPrintTab.tsx b/src/app/footprint/_Components/FootPrintTab/FootPrintTab.tsx new file mode 100644 index 00000000..73c66c0c --- /dev/null +++ b/src/app/footprint/_Components/FootPrintTab/FootPrintTab.tsx @@ -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 ( +
+
+ {TAB_MENU.MY} +
+
+
+ {TAB_MENU.ALL} +
+
+
+ ); +} diff --git a/src/app/footprint/_Components/FootPrintTab/index.scss b/src/app/footprint/_Components/FootPrintTab/index.scss new file mode 100644 index 00000000..61c7b637 --- /dev/null +++ b/src/app/footprint/_Components/FootPrintTab/index.scss @@ -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); + } +} diff --git a/src/app/footprint/_Components/FootprintItem/FootprintItem.tsx b/src/app/footprint/_Components/FootprintItem/FootprintItem.tsx new file mode 100644 index 00000000..f5359365 --- /dev/null +++ b/src/app/footprint/_Components/FootprintItem/FootprintItem.tsx @@ -0,0 +1,78 @@ +import { AjajaButton, Tag } from '@/components'; +import { changeCreatedAtToDate } from '@/utils'; +import classNames from 'classnames'; +import Link from 'next/link'; +import React from 'react'; +import './index.scss'; + +interface FootprintItemProps { + id: number; + iconNumber: number; + title: string; + createdAt: string; + ajajas: number; + tags: string[]; +} + +type FootPrintIconMapType = { + [key: number]: string; +}; + +// TODO: 임시로 정의 +const FOOTPRINT_ICON_MAP: FootPrintIconMapType = { + 0: '🤗', + 1: '🗽', + 2: '🤗', + 3: '🗽', + 4: '🤗', + 5: '🗽', + 6: '🤗', + 7: '🗽', + 8: '🤗', + 9: '🗽', + 10: '🤗', + 11: '🗽', + 12: '🤗', + 13: '🗽', + 14: '🤗', + 15: '🗽', +}; + +export default function FootprintItem({ + id, + iconNumber, + title, + createdAt, + ajajas, + tags, +}: FootprintItemProps) { + return ( +
  • + +
    + {FOOTPRINT_ICON_MAP[iconNumber] + title} +
    +
    + {`${changeCreatedAtToDate(createdAt)} 작성`} +
    + +
    + {tags.map((tagString, idx) => { + return {tagString}; + })} +
    + +
  • + ); +} diff --git a/src/app/footprint/_Components/FootprintItem/index.scss b/src/app/footprint/_Components/FootprintItem/index.scss new file mode 100644 index 00000000..554e6888 --- /dev/null +++ b/src/app/footprint/_Components/FootprintItem/index.scss @@ -0,0 +1,38 @@ +@mixin ellipsis($line) { + text-overflow: ellipsis; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: $line; + -webkit-box-orient: vertical; +} + +.footprint-item { + display: flex; + flex-direction: column; + justify-content: center; + padding: 1.5rem 2rem 1.25rem 2rem; + width: 100%; + box-shadow: var(--origin-shadow); + text-decoration: none; + color: var(--origin-text-100); + + &__title { + @include ellipsis(1); + } + + &__createdAt { + @include ellipsis(1); + margin-left: 0.25rem; + margin-top: 0.5rem; + margin-bottom: 0.75rem; + } + + &__tags { + @include ellipsis(2); + padding-left: 0.2rem; + display: flex; + gap: 0 0.5rem; + height: 2.5rem; + flex-wrap: wrap; + } +} diff --git a/src/app/footprint/_Components/MyFootPrints/MyFootPrints.tsx b/src/app/footprint/_Components/MyFootPrints/MyFootPrints.tsx new file mode 100644 index 00000000..11766092 --- /dev/null +++ b/src/app/footprint/_Components/MyFootPrints/MyFootPrints.tsx @@ -0,0 +1,25 @@ +import { FOOTPRINT_PLAN } from '@/constants'; +import classNames from 'classnames'; +import React, { useState } from 'react'; +import FootPrintFilter from '../FootPrintFilter/FootPrintFilter'; +import FootPrintList from '../FootPrintList/FootPrintList'; +import './index.scss'; + +export type planType = { + planTitle: string; + planId: number; +}; + +export default function MyFootPrints() { + const [year, setYear] = useState(2024); + const [plan, setPlan] = useState(FOOTPRINT_PLAN.ALL_PLAN); + + // Filter에서 검색 버튼을 누르면, setYear와 setPlan이 실행되어 year과 plan이 바뀌면 + // FootPrintList에 변경된 year와 plan이 전달될 것임 + return ( +
    + + +
    + ); +} diff --git a/src/app/footprint/_Components/MyFootPrints/index.scss b/src/app/footprint/_Components/MyFootPrints/index.scss new file mode 100644 index 00000000..bb13768f --- /dev/null +++ b/src/app/footprint/_Components/MyFootPrints/index.scss @@ -0,0 +1,6 @@ +.my-footprints { + height: calc(100% - 2rem - 34px); + display: flex; + flex-direction: column; + gap: 1rem; +} diff --git a/src/app/footprint/index.scss b/src/app/footprint/index.scss new file mode 100644 index 00000000..286513d5 --- /dev/null +++ b/src/app/footprint/index.scss @@ -0,0 +1,7 @@ +.footprint-page { + display: flex; + flex-direction: column; + gap: 1rem; + width: 100%; + height: calc(100% - 1rem); +} diff --git a/src/app/footprint/page.tsx b/src/app/footprint/page.tsx new file mode 100644 index 00000000..de12aba0 --- /dev/null +++ b/src/app/footprint/page.tsx @@ -0,0 +1,30 @@ +'use client'; + +import classNames from 'classnames'; +import { useState } from 'react'; +import AllFootPrints from './_Components/AllFootPrints/AllFootPrints'; +import FootPrintTab from './_Components/FootPrintTab/FootPrintTab'; +import MyFootPrints from './_Components/MyFootPrints/MyFootPrints'; +import './index.scss'; + +export default function FootPrintsPage() { + const [isMyFootPrintsTab, setIsMyFootPrintsTab] = useState(true); + const setMyFootPrintsTab = () => { + setIsMyFootPrintsTab(true); + }; + + const setAllFootPrintsTab = () => { + setIsMyFootPrintsTab(false); + }; + + return ( +
    + + {isMyFootPrintsTab ? : } +
    + ); +} diff --git a/src/components/DebounceSwitchButton/DebounceSwitchButton.tsx b/src/components/DebounceSwitchButton/DebounceSwitchButton.tsx index bae990f1..07dc7058 100644 --- a/src/components/DebounceSwitchButton/DebounceSwitchButton.tsx +++ b/src/components/DebounceSwitchButton/DebounceSwitchButton.tsx @@ -44,7 +44,7 @@ export default function DebounceSwitchButton({ const submitIfReallyChanged = () => { if (isOn !== originalIsOn) { - submitToggleAPI(); + submitToggleAPI(); // TODO: 여기서 만약 실패하면 아래 isOn은 바뀌면 안되는 거 아닌가? setOriginalIsOn(isOn); } }; diff --git a/src/components/Dropdown/index.scss b/src/components/Dropdown/index.scss index fbafb3b3..93ed2e4b 100644 --- a/src/components/Dropdown/index.scss +++ b/src/components/Dropdown/index.scss @@ -24,13 +24,17 @@ justify-content: center; align-items: center; position: relative; - padding: 0.5rem 2rem; + padding: 0.5rem 1rem; border: 1px solid var(--origin-primary); border-radius: var(--border-radius); cursor: pointer; &__text { text-align: center; + width: 6rem; /* 1rem 크기로 고정된 div */ + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; font-size: 1rem; line-height: 1rem; } @@ -82,14 +86,14 @@ } } -.dropdown__remind-option__first{ +.dropdown__remind-option__first { z-index: 13; } -.dropdown__remind-option__second{ +.dropdown__remind-option__second { z-index: 12; } -.dropdown__remind-option__third{ +.dropdown__remind-option__third { z-index: 11; } diff --git a/src/components/Icon/Icon.tsx b/src/components/Icon/Icon.tsx index e80f3476..57175564 100644 --- a/src/components/Icon/Icon.tsx +++ b/src/components/Icon/Icon.tsx @@ -40,6 +40,7 @@ const ICON_NAME_MAP = { COPY: 'content_copy', ARROW_RIGHT: 'subdirectory_arrow_right', CANCEL: 'cancel', + SEARCH: 'search', SHARE: 'share', }; diff --git a/src/constants/footprint.ts b/src/constants/footprint.ts new file mode 100644 index 00000000..36fdccc4 --- /dev/null +++ b/src/constants/footprint.ts @@ -0,0 +1,10 @@ +export const FOOTPRINT_PLAN = { + ALL_PLAN: { + planId: -1, + planTitle: '모든 계획', + }, + EMPTY: { + planId: -2, + planTitle: '계획 없음', + }, +}; diff --git a/src/constants/index.ts b/src/constants/index.ts index fbf3d3a6..eaf3e4d1 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -23,3 +23,4 @@ export { REMIND_TIME_TEXT } from '@/constants/remindTimeText'; export { INPUT_MAX_LENGTH } from '@/constants/userInputMaxLength'; export { address } from '@/constants/addressRegex'; export { options } from '@/constants/radio'; +export { FOOTPRINT_PLAN } from '@/constants/footprint'; diff --git a/src/constants/queryKey.ts b/src/constants/queryKey.ts index 3ce653a6..d0c61e3f 100644 --- a/src/constants/queryKey.ts +++ b/src/constants/queryKey.ts @@ -1,8 +1,10 @@ export const QUERY_KEY = { MY_PLANS: 'getMyPlans', + MY_PLANS_FOR_FOOTPRINT: 'getMyPlans-footprint', ALL_PLANS: 'getAllPlans', PLAN: 'getPlan', REMIND: 'getRemind', USER_INFORMATION: 'getUserInformation', FEEDBACKS: 'getFeedbacks', + MY_FOOTPRINTS: 'getMyFootPrints', }; diff --git a/src/hooks/apis/index.ts b/src/hooks/apis/index.ts index 6137aa7f..00e70e42 100644 --- a/src/hooks/apis/index.ts +++ b/src/hooks/apis/index.ts @@ -4,6 +4,7 @@ export { useEditPlanMutation } from '@/hooks/apis/useEditPlanMutation'; export { useEditRemindMutation } from '@/hooks/apis/useEditRemindMutation'; export { useGetFeedbacksQuery } from '@/hooks/apis/useGetFeedbacksQuery'; export { useGetMyPlansQuery } from '@/hooks/apis/useGetMyPlansQuery'; +export { useGetMyPlansForFootprintQuery } from '@/hooks/apis/useGetMyPlansForFootprintQuery'; export { useGetPlanQuery } from '@/hooks/apis/useGetPlanQuery'; export { useGetRemindQuery } from '@/hooks/apis/useGetRemindQuery'; export { useGetUserInformationQuery } from '@/hooks/apis/useGetUserInformationQuery'; diff --git a/src/hooks/apis/useGetMyPlansForFootprintQuery.ts b/src/hooks/apis/useGetMyPlansForFootprintQuery.ts new file mode 100644 index 00000000..151c076d --- /dev/null +++ b/src/hooks/apis/useGetMyPlansForFootprintQuery.ts @@ -0,0 +1,29 @@ +import { getMyPlans } from '@/apis/client/getMyPlans'; +import { FOOTPRINT_PLAN } from '@/constants'; +import { QUERY_KEY } from '@/constants/queryKey'; +import { useSuspenseQuery } from '@tanstack/react-query'; + +export const useGetMyPlansForFootprintQuery = (year: number) => { + // TODO: year이 바뀔 때마다 이 Query가 다시 호출되지 않고, 호출은 한 번만 되고 + // 바뀌는 year에 따라 select를 통해서 return 하는 data만 바꿔주기 + const { data } = useSuspenseQuery({ + queryKey: [QUERY_KEY.MY_PLANS_FOR_FOOTPRINT], + queryFn: getMyPlans, + staleTime: Infinity, + select: (data) => { + const planData = data.data.find((item) => item.year === year); + return planData + ? [ + FOOTPRINT_PLAN.ALL_PLAN, + ...planData.getPlanList.map((plan) => { + return { + planId: plan.planId, + planTitle: plan.title, + }; + }), + ] + : [FOOTPRINT_PLAN.EMPTY]; + }, + }); + return { yearPlans: data! }; +}; diff --git a/src/hooks/apis/useMyFootPrintsQuery.ts b/src/hooks/apis/useMyFootPrintsQuery.ts new file mode 100644 index 00000000..ea210ddc --- /dev/null +++ b/src/hooks/apis/useMyFootPrintsQuery.ts @@ -0,0 +1,56 @@ +'use client'; + +import { getMyFootPrints } from '@/apis/client/getMyFootPrints'; +import { QUERY_KEY } from '@/constants/queryKey'; +import { GetAllPlansRequestQuery } from '@/types/apis/plan/GetAllPlans'; +import { useSuspenseInfiniteQuery } from '@tanstack/react-query'; + +// TODO: 계획 전체조회 API -> 발자취 전체 조회 API로 수정 필요 +export const useMyFootPrintsQuery = (query: GetAllPlansRequestQuery) => { + const { + data, + fetchNextPage, + hasNextPage, + isLoading, + isFetchingNextPage, + isError, + } = useSuspenseInfiniteQuery({ + queryKey: [QUERY_KEY.MY_FOOTPRINTS, query.sort, query.current], // sort와 current를 쿼리 키에 넣는 게 맞을까? + queryFn: async ({ pageParam = {} }) => { + let params = { + sort: query.sort, + current: query.current, + }; + + if (pageParam) { + // start, ajaja가 들어있을 것임 + params = { ...params, ...pageParam }; + } + + const result = await getMyFootPrints(params); + return result?.data; + }, + initialPageParam: {}, // 초기 pageParam => 빈 객체 + getNextPageParam: (lastPage) => { + // 더 불러올 data가 있는 지 확인하는 함수 + if (lastPage.length === 0) { + // 빈 배열이라면 + return undefined; + } + + const lastItem = lastPage[lastPage.length - 1]; // 가장 최근 받아온 3개 data 중 마지막 item + return query.sort === 'ajaja' + ? { start: lastItem.id, ajaja: lastItem.ajajas } // 인기순이면 start, ajaja 모두 params에 넣어주기 위해 + : { start: lastItem.id }; // 인기순이면 start를 params에 넣어주기 위해 + }, + staleTime: 10000, + }); + return { + tempFootPrintList: data?.pages.flat() || [], // TODO: flat() 없애기 + fetchNextPage, + hasNextPage, + isLoading, + isFetchingNextPage, + isError, + }; +}; diff --git a/src/types/IconName.ts b/src/types/IconName.ts index 0203b284..1e4bc6cd 100644 --- a/src/types/IconName.ts +++ b/src/types/IconName.ts @@ -37,4 +37,5 @@ export type IconName = | 'HELP' | 'ARROW_RIGHT' | 'CANCEL' + | 'SEARCH' | 'SHARE'; diff --git a/src/utils/changeCreatedAtToDate.ts b/src/utils/changeCreatedAtToDate.ts new file mode 100644 index 00000000..d1bd725e --- /dev/null +++ b/src/utils/changeCreatedAtToDate.ts @@ -0,0 +1,4 @@ +export const changeCreatedAtToDate = (createdAt: string) => { + const [yearMonthDate] = createdAt.split('T'); + return yearMonthDate.replace(/-/g, '.'); +}; diff --git a/src/utils/index.ts b/src/utils/index.ts index f25a1c96..76dafa1a 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,4 +1,5 @@ export { alertAndLogin } from '@/utils/alertAndLogin'; +export { changeCreatedAtToDate } from '@/utils/changeCreatedAtToDate'; export { changeRemindTimeToNumber } from '@/utils/changeRemindTimeToNumber'; export { changeRemindTimeToString } from '@/utils/changeRemindTimeToString'; export { checkEmailValidation } from '@/utils/checkEmailValidation';