diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 00000000..7069d16b --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,27 @@ +name: Node.js CI + +on: + pull_request: + branches: + - dev +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [20.x] + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: npm install, and build + run: | + cd src + npm install + npm run build + env: + CI: true diff --git a/.github/workflows/sync-fork.yml b/.github/workflows/sync-fork.yml new file mode 100644 index 00000000..e25a4578 --- /dev/null +++ b/.github/workflows/sync-fork.yml @@ -0,0 +1,32 @@ +name: Synchronize to forked repo +on: + push: + branches: + - main + +jobs: + sync: + name: Sync forked repo + runs-on: ubuntu-latest + + steps: + - name: Checkout main + uses: actions/checkout@v4 + with: + token: ${{ secrets.SYNC_FORK_TOKEN }} + fetch-depth: 0 + ref: main + + - name: Add remote-url + run: | + git remote add forked-repo https://MinwooP:${{ secrets.SYNC_FORK_TOKEN }}@github.com/MinwooP/this-year-ajaja-fe + git config user.name MinwooP + git config user.email alsd20177@gmail.com + + - name: Push changes to forked-repo + run: | + git push -f forked-repo main + + - name: Clean up + run: | + git remote remove forked-repo diff --git a/src/app/(header)/_components/Content.tsx b/src/app/(header)/_components/Content.tsx deleted file mode 100644 index d67009ef..00000000 --- a/src/app/(header)/_components/Content.tsx +++ /dev/null @@ -1,22 +0,0 @@ -'use client'; - -import { ToTopFloatingButton } from '@/components'; -import classNames from 'classnames'; -import { ReactNode } from 'react'; - -type ContentType = { - children: ReactNode; -}; - -export default function Content({ children }: ContentType) { - return ( -
- {children} - -
- ); -} diff --git a/src/app/(header)/_components/Header/Header.tsx b/src/app/(header)/_components/Header/Header.tsx deleted file mode 100644 index fbf4ee4e..00000000 --- a/src/app/(header)/_components/Header/Header.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import classNames from 'classnames'; -import { cookies } from 'next/headers'; -import Image from 'next/image'; -import Link from 'next/link'; -import LinkIconText from '../LinkIconText/LinkIconText'; -import './index.scss'; - -export default function Header() { - const auth = cookies().has('auth'); - const isLogin = auth ? true : false; - return ( -
- - This Year Ajaja Logo - -
- - 다른 계획 둘러보기 - - - {isLogin ? '마이페이지' : '로그인'} - -
-
- ); -} diff --git a/src/app/(header)/_components/Header/index.scss b/src/app/(header)/_components/Header/index.scss deleted file mode 100644 index 9c36181d..00000000 --- a/src/app/(header)/_components/Header/index.scss +++ /dev/null @@ -1,10 +0,0 @@ -.header { - display: flex; - justify-content: space-between; - align-items: center; - height: 6rem; - &__link { - display: flex; - gap: 20px; - } -} diff --git a/src/app/(header)/_components/LinkIconText/LinkIconText.tsx b/src/app/(header)/_components/LinkIconText/LinkIconText.tsx deleted file mode 100644 index c594c9a2..00000000 --- a/src/app/(header)/_components/LinkIconText/LinkIconText.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Icon } from '@/components'; -import { Color } from '@/types'; -import { IconName } from '@/types'; -import classNames from 'classnames'; -import Link from 'next/link'; -import './index.scss'; - -type LinkIconTextProps = { - link: string; - iconName: IconName; - background: Color; - color: Color; - isFilled?: boolean; - border?: Color; - children: React.ReactNode; -}; - -export default function LinkIconText({ - link, - iconName, - background, - color, - isFilled, - border, - children, - ...props -}: LinkIconTextProps) { - return ( - -
- -

- {children} -

-
- - ); -} diff --git a/src/app/(header)/_components/LinkIconText/index.scss b/src/app/(header)/_components/LinkIconText/index.scss deleted file mode 100644 index 8a6656fc..00000000 --- a/src/app/(header)/_components/LinkIconText/index.scss +++ /dev/null @@ -1,19 +0,0 @@ -.link-icon-text { - display: flex; - align-items: center; - width: max-content; - padding: 5px 15px; - &__a { - display: flex; - align-items: center; - text-decoration-line: none; - } - &__text { - padding: 5px; - } -} -@media screen and (max-width: 768px) { - .link-icon-text__text { - display: none; - } -} diff --git a/src/app/(header)/_components/index.scss b/src/app/(header)/_components/index.scss deleted file mode 100644 index ae5299d1..00000000 --- a/src/app/(header)/_components/index.scss +++ /dev/null @@ -1,16 +0,0 @@ -.header-layout { - max-width: 100vw; - height: 100vh; - &__wrapper { - height: 100vh; - width: 90vw; - margin: 0 5vw; - position: relative; - } - &__content { - height: calc(100vh - 6rem); - overflow-y: auto; - border-bottom: 0; - border-radius: var(--border-radius) var(--border-radius) 0 0; - } -} diff --git a/src/app/(header)/home/_components/ProgressBar/ProgressBar.tsx b/src/app/(header)/home/_components/ProgressBar/ProgressBar.tsx deleted file mode 100644 index 9d0cc9b2..00000000 --- a/src/app/(header)/home/_components/ProgressBar/ProgressBar.tsx +++ /dev/null @@ -1,31 +0,0 @@ -'use client'; - -import classNames from 'classnames'; -import { useEffect, useState } from 'react'; -import './index.scss'; - -type ProgressBarProps = { - percent: number; -}; - -export default function ProgressBar({ percent: Maxpercent }: ProgressBarProps) { - const [percent, setPercent] = useState(0); - - useEffect(() => { - const interval = setInterval(() => { - setPercent((pervPercent) => - pervPercent < Maxpercent ? pervPercent + 1 : Maxpercent, - ); - }, 10); - - return () => clearInterval(interval); - }, [Maxpercent]); - return ( -
- -
- ); -} diff --git a/src/app/(header)/plans/[planId]/page.tsx b/src/app/(header)/plans/[planId]/page.tsx deleted file mode 100644 index a28cf7e2..00000000 --- a/src/app/(header)/plans/[planId]/page.tsx +++ /dev/null @@ -1,161 +0,0 @@ -'use client'; - -import { Button, Icon, Modal, ModalBasic, ReadOnlyPlan } from '@/components'; -import KakaoShareButton from '@/components/KakaoShareButton/KakaoShareButton'; -import { ajajaToast } from '@/components/Toaster/customToast'; -import { useDeletePlanMutation } from '@/hooks/apis/useDeletePlanMutation'; -import { useGetPlanQuery } from '@/hooks/apis/useGetPlanQuery'; -import { useIsLogIn } from '@/hooks/useIsLogIn'; -import { isMyPlanStore } from '@/stores/isMyPlanStore'; -import { checkIsSeason } from '@/utils/checkIsSeason'; -import classNames from 'classnames'; -import Link from 'next/link'; -import { useRouter } from 'next/navigation'; -import { useEffect, useState } from 'react'; -import { useSetRecoilState } from 'recoil'; -import NotPublic from './_components/NotPublic/NotPublic'; -import SearchingPlan from './_components/SearchingPlan/SearchingPlan'; -import './index.scss'; - -export default function PlanIdPage({ params }: { params: { planId: string } }) { - const { isLogin } = useIsLogIn(); - const { planId } = params; - const router = useRouter(); - const isSeason = checkIsSeason(); - const [currentURL, setCurrentURL] = useState(''); - const { plan } = useGetPlanQuery(Number(planId), isLogin); - const [isDeletePlanModalOpen, setIsDeletePlanModalOpen] = useState(false); - const [isClientSide, setIsClientSide] = useState(false); - - const { mutate: deletePlanAPI } = useDeletePlanMutation(); - const setIsMyPlanStore = useSetRecoilState(isMyPlanStore); - const isMyPlan = plan.writer.owner; - - // isVisible이라는 변수는 isMyPlan 과 plan.public값에 의해서 정해진다. 하지만 서버에서는 둘 다 undefined이다 그러면 값이 undefined으로 falsy하다. - //그래서 초기html을 받으면 falsy한 html을 받느다. 서버와 클라이언트는 typeof window를 통해서 할 수 있다. - // 또 문제가 이 부분으로 인해 notPublic한 계획도 초기 렌더링시 계획이 보이게된다. 그럼 한번 더싼다. typeof window를 확인해서 - //undefined면 isLoading - useEffect(() => { - if (typeof window !== 'undefined') setIsClientSide(true); - return () => { - setIsClientSide(false); - }; - }, []); - - useEffect(() => { - const current = window.location.href; - setCurrentURL(current); - setIsMyPlanStore(isMyPlan); - return () => { - setIsMyPlanStore(false); - }; - }, [setIsMyPlanStore, isMyPlan]); - - const handleModalClickYes = () => { - setIsDeletePlanModalOpen(false); - deletePlanAPI(parseInt(planId, 10)); - router.push('/home'); - }; - const handleCopyLink = async () => { - await navigator.clipboard.writeText(currentURL); - ajajaToast.success('링크가 복사되었습니다.'); - }; - - const handleModalClickNo = () => { - setIsDeletePlanModalOpen(false); - }; - const handleOpenDeleteModal = () => { - setIsDeletePlanModalOpen(true); - }; - const createPageContent = () => { - if (isClientSide) { - if (isMyPlan || plan.public) { - return ( - - {isMyPlan && isSeason && ( -
- 수정| - 삭제 -
- )} -
- ); - } else { - return ; - } - } else { - return ; - } - }; - - return ( - <> -
-
-
- {isMyPlan ? ( - 홈 - ) : ( - 둘러보기 - )} - > - 계획 -
-
- {createPageContent()} - {isMyPlan && ( -
-

공유하기

-
- - -
-
- )} -
-
- - {isMyPlan && ( -
-
- - - - - - -
-
- )} -
- {isDeletePlanModalOpen && ( - - - 정말 해당 계획을 삭제하시겠습니까 ? - - - )} - - ); -} diff --git a/src/app/(headerless)/login/hooks/useLoginPage.ts b/src/app/(headerless)/login/hooks/useLoginPage.ts deleted file mode 100644 index 6e66f9eb..00000000 --- a/src/app/(headerless)/login/hooks/useLoginPage.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useIsLogIn } from '@/hooks/useIsLogIn'; -import { useRouter } from 'next/navigation'; -import { useEffect } from 'react'; - -export default function useLoginPage() { - const { isLogin } = useIsLogIn(); - const router = useRouter(); - useEffect(() => {}, [isLogin, router]); - - return { isLogin }; -} diff --git a/src/app/_components/Navigation/Navigation.tsx b/src/app/_components/Navigation/Navigation.tsx index 5a8b3ca4..dcd857f5 100644 --- a/src/app/_components/Navigation/Navigation.tsx +++ b/src/app/_components/Navigation/Navigation.tsx @@ -1,56 +1,28 @@ 'use client'; -import { getMyPlans } from '@/apis/client/getMyPlans'; import { Icon } from '@/components'; -import { ajajaToast } from '@/components/Toaster/customToast'; -import { maxPlan } from '@/constants/plan'; -import { canMakeNewPlanStore } from '@/stores/canMakeNewPlanStore'; -import { isMyPlanStore } from '@/stores/isMyPlanStore'; +import { address } from '@/constants'; import { checkIsSeason } from '@/utils/checkIsSeason'; -import { checkThisYear } from '@/utils/checkThisYear'; import classNames from 'classnames'; -import { hasCookie } from 'cookies-next'; import Link from 'next/link'; -import { usePathname } from 'next/navigation'; -import { useEffect, useState } from 'react'; -import { useRecoilState } from 'recoil'; +import { useNavigation } from '../hooks'; import './index.scss'; export default function Navigation({ hasAuth }: { hasAuth: boolean }) { - const pathName = usePathname(); - const [isLogin, setIsLogin] = useState(hasAuth); - const [canMakeNewPlan, setCanMakeNewPlan] = - useRecoilState(canMakeNewPlanStore); - const [isMyPlan] = useRecoilState(isMyPlanStore); - const isEdit = /^\/plans\/edit\/\d+/; - const isPlan = /^\/plans\/\d+/; - const isRemind = /^\/reminds\/.*$/; - const isFeedback = /^\/feedback\/\d+/; - const isFeedbackEvaluate = /^\/feedback\/evaluate/; + const { + pathName, + canMakeNewPlan, + isLogin, + isMyPlan, + isRealLogin, + handleCreate, + } = useNavigation({ + hasAuth, + }); + const { isEdit, isFeedback, isFeedbackEvaluate, isPlan, isRemind } = address; - if (!hasCookie('auth')) { - setTimeout(() => { - setIsLogin(hasCookie('auth')); - }, 1000); - } + isRealLogin(); - const handleCreate = () => { - if (!canMakeNewPlan) { - ajajaToast.error('생성할 수 있는 계획의 수가 최대입니다.'); - } else if (!checkIsSeason()) { - ajajaToast.error('계획을 작성할 수 있는 시즌이 아닙니다.'); - } - }; - - useEffect(() => { - async function isMaxPlan() { - const data = await getMyPlans(); - if (data.data[0]?.year === checkThisYear()) { - setCanMakeNewPlan(!!(maxPlan - data.data[0].getPlanList.length)); - } - } - isMaxPlan(); - }, [setCanMakeNewPlan]); return (
diff --git a/src/app/_components/hooks/index.ts b/src/app/_components/hooks/index.ts new file mode 100644 index 00000000..e48c5e18 --- /dev/null +++ b/src/app/_components/hooks/index.ts @@ -0,0 +1 @@ +export { default as useNavigation } from './useNavigation'; diff --git a/src/app/_components/hooks/useNavigation.ts b/src/app/_components/hooks/useNavigation.ts new file mode 100644 index 00000000..bddde832 --- /dev/null +++ b/src/app/_components/hooks/useNavigation.ts @@ -0,0 +1,54 @@ +import { getMyPlans } from '@/apis/client/getMyPlans'; +import { ajajaToast } from '@/components/Toaster/customToast'; +import { maxPlan } from '@/constants/plan'; +import { canMakeNewPlanStore } from '@/stores/canMakeNewPlanStore'; +import { isMyPlanStore } from '@/stores/isMyPlanStore'; +import { checkIsSeason } from '@/utils/checkIsSeason'; +import { checkThisYear } from '@/utils/checkThisYear'; +import { hasCookie } from 'cookies-next'; +import { usePathname } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { useRecoilState } from 'recoil'; + +export default function useNavigation({ hasAuth }: { hasAuth: boolean }) { + const pathName = usePathname(); + const [isLogin, setIsLogin] = useState(hasAuth); + const [canMakeNewPlan, setCanMakeNewPlan] = + useRecoilState(canMakeNewPlanStore); + const [isMyPlan] = useRecoilState(isMyPlanStore); + const isRealLogin = () => { + if (!hasCookie('auth')) { + setTimeout(() => { + setIsLogin(hasCookie('auth')); + }, 1000); + } + }; + const handleCreate = () => { + if (!canMakeNewPlan) { + ajajaToast.error('생성할 수 있는 계획의 수가 최대입니다.'); + } else if (!checkIsSeason()) { + ajajaToast.error('계획을 작성할 수 있는 시즌이 아닙니다.'); + } + }; + + useEffect(() => { + async function isMaxPlan() { + const data = await getMyPlans(); + if (data.data[0]?.year === checkThisYear()) { + setCanMakeNewPlan(!!(maxPlan - data.data[0].getPlanList.length)); + } + } + + isMaxPlan(); + }, [setCanMakeNewPlan]); + + return { + pathName, + isLogin, + setIsLogin, + canMakeNewPlan, + isMyPlan, + isRealLogin, + handleCreate, + }; +} diff --git a/src/app/(header)/create/_components/CreatePlanStepper/CreatePlanStepper.tsx b/src/app/create/_components/CreatePlanStepper/CreatePlanStepper.tsx similarity index 100% rename from src/app/(header)/create/_components/CreatePlanStepper/CreatePlanStepper.tsx rename to src/app/create/_components/CreatePlanStepper/CreatePlanStepper.tsx diff --git a/src/app/(header)/create/_components/CreatePlanStepper/index.scss b/src/app/create/_components/CreatePlanStepper/index.scss similarity index 100% rename from src/app/(header)/create/_components/CreatePlanStepper/index.scss rename to src/app/create/_components/CreatePlanStepper/index.scss diff --git a/src/app/(header)/create/_components/StepButtonGroup/StepButtonGroup.tsx b/src/app/create/_components/StepButtonGroup/StepButtonGroup.tsx similarity index 96% rename from src/app/(header)/create/_components/StepButtonGroup/StepButtonGroup.tsx rename to src/app/create/_components/StepButtonGroup/StepButtonGroup.tsx index 88ccc169..49e741aa 100644 --- a/src/app/(header)/create/_components/StepButtonGroup/StepButtonGroup.tsx +++ b/src/app/create/_components/StepButtonGroup/StepButtonGroup.tsx @@ -4,9 +4,8 @@ import { Button } from '@/components'; import { ajajaToast } from '@/components/Toaster/customToast'; import { SESSION_STORAGE_KEY } from '@/constants'; import { usePostNewPlanMutation } from '@/hooks/apis/usePostNewPlanMutation'; -import { PlanContentType } from '@/types/Plan'; -import { RemindItemType, RemindOptionType } from '@/types/Remind'; -import { PostNewPlanRequestBody } from '@/types/apis/plan/PostNewPlan'; +import { PlanContentType, RemindItemType, RemindOptionType } from '@/types'; +import { PostNewPlanRequestBody } from '@/types/apis'; import { changeRemindTimeToString } from '@/utils/changeRemindTimeToString'; import classNames from 'classnames'; import { useRouter } from 'next/navigation'; diff --git a/src/app/(header)/create/_components/StepButtonGroup/index.scss b/src/app/create/_components/StepButtonGroup/index.scss similarity index 100% rename from src/app/(header)/create/_components/StepButtonGroup/index.scss rename to src/app/create/_components/StepButtonGroup/index.scss diff --git a/src/app/(header)/create/error.tsx b/src/app/create/error.tsx similarity index 100% rename from src/app/(header)/create/error.tsx rename to src/app/create/error.tsx diff --git a/src/app/(header)/create/index.scss b/src/app/create/index.scss similarity index 100% rename from src/app/(header)/create/index.scss rename to src/app/create/index.scss diff --git a/src/app/(header)/create/page.tsx b/src/app/create/page.tsx similarity index 96% rename from src/app/(header)/create/page.tsx rename to src/app/create/page.tsx index 5219d13e..202bcf79 100644 --- a/src/app/(header)/create/page.tsx +++ b/src/app/create/page.tsx @@ -5,14 +5,13 @@ import { CreatePlanIcon, CreatePlanRemindDate, CreatePlanRemindMessage, + ModalContinueCreate, ModalFixRemindDate, } from '@/components'; -import ModalContinueCreate from '@/components/ModalContinueCreate/ModalContinueCreate'; import { ajajaToast } from '@/components/Toaster/customToast'; -import { SESSION_STORAGE_KEY } from '@/constants'; -import { STEP_NAME } from '@/constants/createPlanStepTitle'; +import { SESSION_STORAGE_KEY, STEP_NAME } from '@/constants'; import { canMakeNewPlanStore } from '@/stores/canMakeNewPlanStore'; -import { RemindItemType, RemindOptionType } from '@/types/Remind'; +import { RemindItemType, RemindOptionType } from '@/types'; import { decideRemindDate } from '@/utils/decideRemindDate'; import { getSessionStorageData } from '@/utils/getSessionStorageData'; import classNames from 'classnames'; diff --git a/src/app/(header)/explore/_components/Card/Card.tsx b/src/app/explore/_components/Card/Card.tsx similarity index 100% rename from src/app/(header)/explore/_components/Card/Card.tsx rename to src/app/explore/_components/Card/Card.tsx diff --git a/src/app/(header)/explore/_components/Card/index.scss b/src/app/explore/_components/Card/index.scss similarity index 100% rename from src/app/(header)/explore/_components/Card/index.scss rename to src/app/explore/_components/Card/index.scss diff --git a/src/app/(header)/explore/_components/ExplorePlans.tsx b/src/app/explore/_components/ExplorePlans.tsx similarity index 66% rename from src/app/(header)/explore/_components/ExplorePlans.tsx rename to src/app/explore/_components/ExplorePlans.tsx index a6e2b6fa..f0a15f7b 100644 --- a/src/app/(header)/explore/_components/ExplorePlans.tsx +++ b/src/app/explore/_components/ExplorePlans.tsx @@ -2,30 +2,22 @@ import { ToTopFloatingButton } from '@/components'; import { COLOR } from '@/constants'; -import { useAllPlansQuery } from '@/hooks/apis/useAllPlansQuery'; -import { SortType } from '@/types/apis/plan/GetAllPlans'; import classNames from 'classnames'; -import { useMemo, useState } from 'react'; import InfiniteScroll from 'react-infinite-scroller'; import { FadeLoader } from 'react-spinners'; import Plans from './Plans/Plans'; import Tab from './Tab/Tab'; +import { useExplorePlans } from './hooks'; import './index.scss'; export default function ExplorePlans() { - const [sort, setSort] = useState('latest'); - const [current, setCurrent] = useState(true); - const { loadedPlans, fetchNextPage, hasNextPage } = useAllPlansQuery({ - sort, - current, - }); - const flatLoadedPlans = useMemo(() => loadedPlans.flat(), [loadedPlans]); - const handleSort = (condition: SortType) => { - setSort(condition); - }; - const handleYear = (isNewYear: boolean) => { - setCurrent(isNewYear); - }; + const { + fetchNextPage, + flatLoadedPlans, + handleSort, + handleYear, + hasNextPage, + } = useExplorePlans(); return (
diff --git a/src/app/(header)/explore/_components/Plans/Plans.tsx b/src/app/explore/_components/Plans/Plans.tsx similarity index 100% rename from src/app/(header)/explore/_components/Plans/Plans.tsx rename to src/app/explore/_components/Plans/Plans.tsx diff --git a/src/app/(header)/explore/_components/Plans/index.scss b/src/app/explore/_components/Plans/index.scss similarity index 100% rename from src/app/(header)/explore/_components/Plans/index.scss rename to src/app/explore/_components/Plans/index.scss diff --git a/src/app/(header)/explore/_components/Tab/Tab.tsx b/src/app/explore/_components/Tab/Tab.tsx similarity index 77% rename from src/app/(header)/explore/_components/Tab/Tab.tsx rename to src/app/explore/_components/Tab/Tab.tsx index 1c71abc8..5f6ec0c2 100644 --- a/src/app/(header)/explore/_components/Tab/Tab.tsx +++ b/src/app/explore/_components/Tab/Tab.tsx @@ -1,19 +1,18 @@ 'use client'; -import { SortType } from '@/types/apis/plan/GetAllPlans'; +import { TabProps } from '@/types'; import classNames from 'classnames'; -import { useState } from 'react'; import React from 'react'; +import { useTab } from '../hooks'; import './index.scss'; -type TabProps = { - handleSort: (condition: SortType) => void; - handleYear: (isNewYear: boolean) => void; -}; - export default function Tab({ handleSort, handleYear }: TabProps) { - const [currentYearTab, setCurrentYearTab] = useState(0); - const [currentSortTab, setCurrentSortTab] = useState(0); + const { + currentSortTab, + currentYearTab, + selectSortMenuHandler, + selectYearMenuHandler, + } = useTab({ handleSort, handleYear }); const yearMenu = [ { name: '새해' }, @@ -23,14 +22,6 @@ export default function Tab({ handleSort, handleYear }: TabProps) { ]; const sortMenu = [{ name: '최신순' }, { name: '인기순' }]; - const selectYearMenuHandler = (index: number) => { - setCurrentYearTab(index); - handleYear(index === 0 ? true : false); - }; - const selectSortMenuHandler = (index: number) => { - setCurrentSortTab(index); - handleSort(index === 0 ? 'latest' : 'ajaja'); - }; return (
diff --git a/src/app/(header)/explore/_components/Tab/index.scss b/src/app/explore/_components/Tab/index.scss similarity index 100% rename from src/app/(header)/explore/_components/Tab/index.scss rename to src/app/explore/_components/Tab/index.scss diff --git a/src/app/explore/_components/hooks/index.ts b/src/app/explore/_components/hooks/index.ts new file mode 100644 index 00000000..3c17e674 --- /dev/null +++ b/src/app/explore/_components/hooks/index.ts @@ -0,0 +1,2 @@ +export { default as useTab } from './useTab'; +export { default as useExplorePlans } from './useExplorePlans'; diff --git a/src/app/explore/_components/hooks/useExplorePlans.ts b/src/app/explore/_components/hooks/useExplorePlans.ts new file mode 100644 index 00000000..d9d96115 --- /dev/null +++ b/src/app/explore/_components/hooks/useExplorePlans.ts @@ -0,0 +1,31 @@ +import { useAllPlansQuery } from '@/hooks/apis/useAllPlansQuery'; +import { SortType } from '@/types/apis/plan/GetAllPlans'; +import { useMemo, useState } from 'react'; + +export default function useExplorePlans() { + const [sort, setSort] = useState('latest'); + const [current, setCurrent] = useState(true); + const { loadedPlans, fetchNextPage, hasNextPage } = useAllPlansQuery({ + sort, + current, + }); + const flatLoadedPlans = useMemo(() => loadedPlans.flat(), [loadedPlans]); + const handleSort = (condition: SortType) => { + setSort(condition); + }; + const handleYear = (isNewYear: boolean) => { + setCurrent(isNewYear); + }; + return { + sort, + setSort, + current, + setCurrent, + loadedPlans, + fetchNextPage, + hasNextPage, + flatLoadedPlans, + handleSort, + handleYear, + }; +} diff --git a/src/app/explore/_components/hooks/useTab.ts b/src/app/explore/_components/hooks/useTab.ts new file mode 100644 index 00000000..21d31d51 --- /dev/null +++ b/src/app/explore/_components/hooks/useTab.ts @@ -0,0 +1,23 @@ +import { TabProps } from '@/types/Tab'; +import { useState } from 'react'; + +export default function useTab({ handleSort, handleYear }: TabProps) { + const [currentYearTab, setCurrentYearTab] = useState(0); + const [currentSortTab, setCurrentSortTab] = useState(0); + const selectYearMenuHandler = (index: number) => { + setCurrentYearTab(index); + handleYear(index === 0 ? true : false); + }; + const selectSortMenuHandler = (index: number) => { + setCurrentSortTab(index); + handleSort(index === 0 ? 'latest' : 'ajaja'); + }; + return { + currentYearTab, + setCurrentYearTab, + currentSortTab, + setCurrentSortTab, + selectYearMenuHandler, + selectSortMenuHandler, + }; +} diff --git a/src/app/(header)/explore/_components/index.scss b/src/app/explore/_components/index.scss similarity index 100% rename from src/app/(header)/explore/_components/index.scss rename to src/app/explore/_components/index.scss diff --git a/src/app/(header)/explore/error.tsx b/src/app/explore/error.tsx similarity index 100% rename from src/app/(header)/explore/error.tsx rename to src/app/explore/error.tsx diff --git a/src/app/(header)/explore/page.tsx b/src/app/explore/page.tsx similarity index 100% rename from src/app/(header)/explore/page.tsx rename to src/app/explore/page.tsx diff --git a/src/app/feedback/[planId]/_components/hooks/index.ts b/src/app/feedback/[planId]/_components/hooks/index.ts new file mode 100644 index 00000000..af0496ea --- /dev/null +++ b/src/app/feedback/[planId]/_components/hooks/index.ts @@ -0,0 +1 @@ +export { default as usePlanIdPage } from './usePlanIdPage'; diff --git a/src/app/feedback/[planId]/_components/hooks/usePlanIdPage.ts b/src/app/feedback/[planId]/_components/hooks/usePlanIdPage.ts new file mode 100644 index 00000000..6b195b41 --- /dev/null +++ b/src/app/feedback/[planId]/_components/hooks/usePlanIdPage.ts @@ -0,0 +1,28 @@ +import { useGetFeedbacksQuery } from '@/hooks/apis/useGetFeedbacksQuery'; + +export default function usePlanIdPage({ + params, +}: { + params: { planId: string }; +}) { + const { planId } = params; + const { feedback } = useGetFeedbacksQuery(parseInt(planId, 10)); + const { achieveRate, title, feedbacks } = feedback; + let plan_evaluate_text = ''; + + if (achieveRate >= 80) { + plan_evaluate_text = '매우 잘 지키고 있어요!'; + } else if (achieveRate >= 50) { + plan_evaluate_text = '잘 지키고 있어요!'; + } else { + plan_evaluate_text = '잘 지켜주세요!'; + } + return { + planId, + feedback, + achieveRate, + title, + feedbacks, + plan_evaluate_text, + }; +} diff --git a/src/app/feedback/[planId]/page.tsx b/src/app/feedback/[planId]/page.tsx index ea450058..2da8f962 100644 --- a/src/app/feedback/[planId]/page.tsx +++ b/src/app/feedback/[planId]/page.tsx @@ -2,11 +2,11 @@ import { Button } from '@/components'; import FeedbackItem from '@/components/FeedbackItem/FeedbackItem'; -import { useGetFeedbacksQuery } from '@/hooks/apis/useGetFeedbacksQuery'; import classNames from 'classnames'; import Link from 'next/link'; import { CircularProgressbar } from 'react-circular-progressbar'; import 'react-circular-progressbar/dist/styles.css'; +import { usePlanIdPage } from './_components/hooks'; import './_components/index.scss'; export default function FeedbackPage({ @@ -14,19 +14,16 @@ export default function FeedbackPage({ }: { params: { planId: string }; }) { - const { planId } = params; - const { feedback } = useGetFeedbacksQuery(parseInt(planId, 10)); - const { achieveRate, title, feedbacks } = feedback; - let plan_evaluate_text = ''; - - if (achieveRate >= 80) { - plan_evaluate_text = '매우 잘 지키고 있어요!'; - } else if (achieveRate >= 50) { - plan_evaluate_text = '잘 지키고 있어요!'; - } else { - plan_evaluate_text = '잘 지켜주세요!'; - } - + const { + planId, + feedback, + achieveRate, + feedbacks, + plan_evaluate_text, + title, + } = usePlanIdPage({ + params, + }); return (
diff --git a/src/app/feedback/evaluate/_components/EvaluateRadio.tsx b/src/app/feedback/evaluate/_components/EvaluateRadio.tsx index 9f8ca7da..1768ab6e 100644 --- a/src/app/feedback/evaluate/_components/EvaluateRadio.tsx +++ b/src/app/feedback/evaluate/_components/EvaluateRadio.tsx @@ -1,32 +1,13 @@ +import { options } from '@/constants'; +import { EvaluateRadioProps } from '@/types'; import classNames from 'classnames'; -import { ChangeEvent } from 'react'; - -type EvaluateRadioProps = { - evaluateOption: number; - setEvaluateOption: React.Dispatch>; -}; - -type Option = { - value: string; - label: string; -}; +import { useEvaluateRadio } from './hooks'; export default function EvaluateRadio({ evaluateOption, setEvaluateOption, }: EvaluateRadioProps) { - const options: Option[] = [ - { value: '100', label: '매우 잘함 (100%)' }, - { value: '75', label: '잘 함 (75%)' }, - { value: '50', label: '보통 (50%)' }, - { value: '25', label: '대체로 못함 (25%)' }, - { value: '0', label: '전혀 못함 (0%)' }, - ]; - - const handleOptionChange = (event: ChangeEvent) => { - setEvaluateOption(parseInt(event.target.value, 10)); - }; - + const { handleOptionChange } = useEvaluateRadio({ setEvaluateOption }); return (
{options.map((option) => ( diff --git a/src/app/feedback/evaluate/_components/hooks/index.ts b/src/app/feedback/evaluate/_components/hooks/index.ts new file mode 100644 index 00000000..1cdf628f --- /dev/null +++ b/src/app/feedback/evaluate/_components/hooks/index.ts @@ -0,0 +1,2 @@ +export { default as useEvaluateRadio } from './useEvaluateRadio'; +export { default as useEvaluatePage } from './useEvaluatePage'; diff --git a/src/app/feedback/evaluate/_components/hooks/useEvaluatePage.ts b/src/app/feedback/evaluate/_components/hooks/useEvaluatePage.ts new file mode 100644 index 00000000..818cc350 --- /dev/null +++ b/src/app/feedback/evaluate/_components/hooks/useEvaluatePage.ts @@ -0,0 +1,77 @@ +import { usePostFeedbacksMutation } from '@/hooks/apis/usePostFeedbacksMutation'; +import { AxiosError } from 'axios'; +import { useSearchParams } from 'next/navigation'; +import { useState } from 'react'; + +export default function useEvaluatePage() { + const searchParams = useSearchParams(); + const title = searchParams.get('title'); + const month = searchParams.get('month'); + const day = searchParams.get('day'); + const planId = searchParams.get('planId'); + + const [evaluateOption, setEvaluateOption] = useState(100); + const [evaluateMessage, setEvaluateMessage] = useState(''); + const [errorCode, setErrorCode] = useState(); + const [errorMessage, setErrorMessage] = useState(''); + const [isFeedbackSendModalOpen, setIsFeedbackSendModalOpen] = useState(false); + const { mutate: postFeedbacks, error } = usePostFeedbacksMutation( + parseInt(planId as string, 10), + ); + + if (error) { + const axiosError = error as AxiosError; + const status = axiosError.response?.status; + if (status && status !== errorCode) { + setErrorCode(status); + switch (status) { + case 400: + setErrorMessage('피드백 기간이 아닙니다!'); + break; + case 409: + setErrorMessage('이미 평가된 피드백입니다!'); + break; + } + } + } + + const handleChangeMessage = (changedMessage: string) => { + setEvaluateMessage(changedMessage); + }; + + const handleModalClickNo = () => { + setIsFeedbackSendModalOpen(false); + }; + const handleModalClickYes = () => { + postFeedbacks({ + planId: parseInt(planId as string, 10), + body: { rate: evaluateOption, message: evaluateMessage }, + }); + }; + const handleModalOpen = () => { + setIsFeedbackSendModalOpen(true); + }; + return { + searchParams, + title, + month, + day, + planId, + evaluateOption, + setEvaluateOption, + evaluateMessage, + setEvaluateMessage, + errorCode, + setErrorCode, + errorMessage, + setErrorMessage, + isFeedbackSendModalOpen, + setIsFeedbackSendModalOpen, + postFeedbacks, + error, + handleChangeMessage, + handleModalClickNo, + handleModalClickYes, + handleModalOpen, + }; +} diff --git a/src/app/feedback/evaluate/_components/hooks/useEvaluateRadio.ts b/src/app/feedback/evaluate/_components/hooks/useEvaluateRadio.ts new file mode 100644 index 00000000..1cb7861b --- /dev/null +++ b/src/app/feedback/evaluate/_components/hooks/useEvaluateRadio.ts @@ -0,0 +1,12 @@ +import { ChangeEvent } from 'react'; + +export default function useEvaluateRadio({ + setEvaluateOption, +}: { + setEvaluateOption: React.Dispatch>; +}) { + const handleOptionChange = (event: ChangeEvent) => { + setEvaluateOption(parseInt(event.target.value, 10)); + }; + return { handleOptionChange }; +} diff --git a/src/app/feedback/evaluate/page.tsx b/src/app/feedback/evaluate/page.tsx index ec9958b8..096950b0 100644 --- a/src/app/feedback/evaluate/page.tsx +++ b/src/app/feedback/evaluate/page.tsx @@ -2,63 +2,29 @@ import { Button, Modal, ModalBasic, PlanInput } from '@/components'; import WrongApproach from '@/components/WrongApproach/WrongApproach'; -import { usePostFeedbacksMutation } from '@/hooks/apis/usePostFeedbacksMutation'; -import { AxiosError } from 'axios'; import classNames from 'classnames'; import Link from 'next/link'; -import { useSearchParams } from 'next/navigation'; -import { useState } from 'react'; import EvaluateRadio from './_components/EvaluateRadio'; +import { useEvaluatePage } from './_components/hooks'; import './_components/index.scss'; export default function FeedbackPage() { - const searchParams = useSearchParams(); - const title = searchParams.get('title'); - const month = searchParams.get('month'); - const day = searchParams.get('day'); - const planId = searchParams.get('planId'); - - const [evaluateOption, setEvaluateOption] = useState(100); - const [evaluateMessage, setEvaluateMessage] = useState(''); - const [errorCode, setErrorCode] = useState(); - const [errorMessage, setErrorMessage] = useState(''); - const [isFeedbackSendModalOpen, setIsFeedbackSendModalOpen] = useState(false); - const { mutate: postFeedbacks, error } = usePostFeedbacksMutation( - parseInt(planId as string, 10), - ); - - if (error) { - const axiosError = error as AxiosError; - const status = axiosError.response?.status; - if (status && status !== errorCode) { - setErrorCode(status); - switch (status) { - case 400: - setErrorMessage('피드백 기간이 아닙니다!'); - break; - case 409: - setErrorMessage('이미 평가된 피드백입니다!'); - break; - } - } - } - - const handleChangeMessage = (changedMessage: string) => { - setEvaluateMessage(changedMessage); - }; - - const handleModalClickNo = () => { - setIsFeedbackSendModalOpen(false); - }; - const handleModalClickYes = () => { - postFeedbacks({ - planId: parseInt(planId as string, 10), - body: { rate: evaluateOption, message: evaluateMessage }, - }); - }; - const handleModalOpen = () => { - setIsFeedbackSendModalOpen(true); - }; + const { + day, + errorCode, + errorMessage, + evaluateMessage, + evaluateOption, + handleChangeMessage, + handleModalClickNo, + handleModalClickYes, + handleModalOpen, + isFeedbackSendModalOpen, + month, + planId, + setEvaluateOption, + title, + } = useEvaluatePage(); return (
diff --git a/src/app/(header)/home/_components/MyPlan.tsx b/src/app/home/_components/MyPlan.tsx similarity index 68% rename from src/app/(header)/home/_components/MyPlan.tsx rename to src/app/home/_components/MyPlan.tsx index 037ed5a1..7b18e6e6 100644 --- a/src/app/(header)/home/_components/MyPlan.tsx +++ b/src/app/home/_components/MyPlan.tsx @@ -3,41 +3,19 @@ import { Dropdown } from '@/components'; import { maxPlan } from '@/constants/plan'; import { planIcons } from '@/constants/planIcons'; -import { canMakeNewPlanStore } from '@/stores/canMakeNewPlanStore'; import { GetMyPlansResponse } from '@/types/apis/plan/GetMyPlans'; import { checkThisYear } from '@/utils/checkThisYear'; import classNames from 'classnames'; import Image from 'next/image'; -import { useEffect, useState } from 'react'; -import { useSetRecoilState } from 'recoil'; import NewPlan from './NewPlan/NewPlan'; import Plan from './Plan/Plan'; import ProgressBar from './ProgressBar/ProgressBar'; +import { useMyPlan } from './hooks'; -type MyPlanProps = { - myPlans: GetMyPlansResponse; -}; - -export default function MyPlan({ myPlans }: MyPlanProps) { - const { data: myPlansData } = myPlans; - const yearList = myPlansData.map((x) => x.year); - const setCanMakeNewPlan = useSetRecoilState(canMakeNewPlanStore); - const [year, setYear] = useState(yearList[0]); - const [yearData, setYearData] = useState(myPlansData[0]); - const [yearDataLength, setYearDataLength] = useState( - myPlansData[0].getPlanList.length, +export default function MyPlan({ myPlans }: { myPlans: GetMyPlansResponse }) { + const { PERIOD_OPTIONS, setYear, year, yearData, yearDataLength } = useMyPlan( + { myPlans }, ); - - const PERIOD_OPTIONS = yearList.map((x) => { - return { value: x, name: `${x}년 계획` }; - }); - - useEffect(() => { - const chosenYearData = myPlansData.find((x) => x.year === year)!; - setYearData(chosenYearData); - setYearDataLength(chosenYearData.getPlanList.length); - setCanMakeNewPlan(!!(maxPlan - chosenYearData.getPlanList.length)); - }, [year, myPlansData, setYearDataLength, setCanMakeNewPlan]); return ( <>
diff --git a/src/app/(header)/home/_components/NewPlan/NewPlan.tsx b/src/app/home/_components/NewPlan/NewPlan.tsx similarity index 91% rename from src/app/(header)/home/_components/NewPlan/NewPlan.tsx rename to src/app/home/_components/NewPlan/NewPlan.tsx index b5e44420..a6ebc212 100644 --- a/src/app/(header)/home/_components/NewPlan/NewPlan.tsx +++ b/src/app/home/_components/NewPlan/NewPlan.tsx @@ -1,14 +1,12 @@ import { Icon } from '@/components'; -import { canMakeNewPlanStore } from '@/stores/canMakeNewPlanStore'; import { checkIsSeason } from '@/utils/checkIsSeason'; import classNames from 'classnames'; import Link from 'next/link'; -import { useRecoilState } from 'recoil'; +import { useNewPlan } from '../hooks'; import './index.scss'; export default function NewPlan() { - const [canMakeNewPlan] = useRecoilState(canMakeNewPlanStore); - + const { canMakeNewPlan } = useNewPlan(); return ( <>
diff --git a/src/app/(header)/home/_components/NewPlan/index.scss b/src/app/home/_components/NewPlan/index.scss similarity index 100% rename from src/app/(header)/home/_components/NewPlan/index.scss rename to src/app/home/_components/NewPlan/index.scss diff --git a/src/app/(header)/home/_components/Plan/Plan.tsx b/src/app/home/_components/Plan/Plan.tsx similarity index 100% rename from src/app/(header)/home/_components/Plan/Plan.tsx rename to src/app/home/_components/Plan/Plan.tsx diff --git a/src/app/(header)/home/_components/Plan/index.scss b/src/app/home/_components/Plan/index.scss similarity index 100% rename from src/app/(header)/home/_components/Plan/index.scss rename to src/app/home/_components/Plan/index.scss diff --git a/src/app/home/_components/ProgressBar/ProgressBar.tsx b/src/app/home/_components/ProgressBar/ProgressBar.tsx new file mode 100644 index 00000000..04b12025 --- /dev/null +++ b/src/app/home/_components/ProgressBar/ProgressBar.tsx @@ -0,0 +1,19 @@ +'use client'; + +import { ProgressBarProps } from '@/types'; +import classNames from 'classnames'; +import { useProgressBar } from '../hooks'; +import './index.scss'; + +export default function ProgressBar({ percent: Maxpercent }: ProgressBarProps) { + const { percent } = useProgressBar({ percent: Maxpercent }); + + return ( +
+ +
+ ); +} diff --git a/src/app/(header)/home/_components/ProgressBar/index.scss b/src/app/home/_components/ProgressBar/index.scss similarity index 100% rename from src/app/(header)/home/_components/ProgressBar/index.scss rename to src/app/home/_components/ProgressBar/index.scss diff --git a/src/app/home/_components/hooks/index.ts b/src/app/home/_components/hooks/index.ts new file mode 100644 index 00000000..a5a35a71 --- /dev/null +++ b/src/app/home/_components/hooks/index.ts @@ -0,0 +1,4 @@ +export { default as useNewPlan } from './useNewPlan'; +export { default as useProgressBar } from './useProgressBar'; +export { default as useMyPlan } from './useMyPlan'; +export { default as useHomePage } from './useHomePage'; diff --git a/src/app/(header)/home/page.tsx b/src/app/home/_components/hooks/useHomePage.ts similarity index 54% rename from src/app/(header)/home/page.tsx rename to src/app/home/_components/hooks/useHomePage.ts index 1be70dae..931f30a4 100644 --- a/src/app/(header)/home/page.tsx +++ b/src/app/home/_components/hooks/useHomePage.ts @@ -1,12 +1,7 @@ -'use client'; - import { useGetMyPlansQuery } from '@/hooks/apis/useGetMyPlansQuery'; import { checkThisYear } from '@/utils/checkThisYear'; -import classNames from 'classnames'; -import MyPlan from './_components/MyPlan'; -import './_components/index.scss'; -export default function HomePage() { +export default function useHomePage() { const { myPlans } = useGetMyPlansQuery(); if (!myPlans.data.length || myPlans.data[0].year !== checkThisYear()) { @@ -16,12 +11,5 @@ export default function HomePage() { getPlanList: [], }); } - - return ( - <> -
- -
- - ); + return { myPlans }; } diff --git a/src/app/home/_components/hooks/useMyPlan.ts b/src/app/home/_components/hooks/useMyPlan.ts new file mode 100644 index 00000000..acc51c9e --- /dev/null +++ b/src/app/home/_components/hooks/useMyPlan.ts @@ -0,0 +1,43 @@ +import { maxPlan } from '@/constants/plan'; +import { canMakeNewPlanStore } from '@/stores/canMakeNewPlanStore'; +import { GetMyPlansResponse } from '@/types/apis'; +import { useEffect, useState } from 'react'; +import { useSetRecoilState } from 'recoil'; + +export default function useMyPlan({ + myPlans, +}: { + myPlans: GetMyPlansResponse; +}) { + const { data: myPlansData } = myPlans; + const yearList = myPlansData.map((x) => x.year); + const setCanMakeNewPlan = useSetRecoilState(canMakeNewPlanStore); + const [year, setYear] = useState(yearList[0]); + const [yearData, setYearData] = useState(myPlansData[0]); + const [yearDataLength, setYearDataLength] = useState( + myPlansData[0].getPlanList.length, + ); + + const PERIOD_OPTIONS = yearList.map((x) => { + return { value: x, name: `${x}년 계획` }; + }); + + useEffect(() => { + const chosenYearData = myPlansData.find((x) => x.year === year)!; + setYearData(chosenYearData); + setYearDataLength(chosenYearData.getPlanList.length); + setCanMakeNewPlan(!!(maxPlan - chosenYearData.getPlanList.length)); + }, [year, myPlansData, setYearDataLength, setCanMakeNewPlan]); + return { + myPlansData, + yearList, + setCanMakeNewPlan, + year, + setYear, + yearData, + setYearData, + yearDataLength, + setYearDataLength, + PERIOD_OPTIONS, + }; +} diff --git a/src/app/home/_components/hooks/useNewPlan.ts b/src/app/home/_components/hooks/useNewPlan.ts new file mode 100644 index 00000000..0b038742 --- /dev/null +++ b/src/app/home/_components/hooks/useNewPlan.ts @@ -0,0 +1,8 @@ +import { canMakeNewPlanStore } from '@/stores/canMakeNewPlanStore'; +import { useRecoilState } from 'recoil'; + +export default function useNewPlan() { + const [canMakeNewPlan] = useRecoilState(canMakeNewPlanStore); + + return { canMakeNewPlan }; +} diff --git a/src/app/home/_components/hooks/useProgressBar.ts b/src/app/home/_components/hooks/useProgressBar.ts new file mode 100644 index 00000000..58349552 --- /dev/null +++ b/src/app/home/_components/hooks/useProgressBar.ts @@ -0,0 +1,20 @@ +import { ProgressBarProps } from '@/types'; +import { useEffect, useState } from 'react'; + +export default function useProgressBar({ + percent: Maxpercent, +}: ProgressBarProps) { + const [percent, setPercent] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setPercent((pervPercent) => + pervPercent < Maxpercent ? pervPercent + 1 : Maxpercent, + ); + }, 10); + + return () => clearInterval(interval); + }, [Maxpercent]); + + return { percent, setPercent }; +} diff --git a/src/app/(header)/home/_components/index.scss b/src/app/home/_components/index.scss similarity index 100% rename from src/app/(header)/home/_components/index.scss rename to src/app/home/_components/index.scss diff --git a/src/app/(header)/home/error.tsx b/src/app/home/error.tsx similarity index 100% rename from src/app/(header)/home/error.tsx rename to src/app/home/error.tsx diff --git a/src/app/home/page.tsx b/src/app/home/page.tsx new file mode 100644 index 00000000..388ce776 --- /dev/null +++ b/src/app/home/page.tsx @@ -0,0 +1,18 @@ +'use client'; + +import classNames from 'classnames'; +import MyPlan from './_components/MyPlan'; +import { useHomePage } from './_components/hooks'; +import './_components/index.scss'; + +export default function HomePage() { + const { myPlans } = useHomePage(); + + return ( + <> +
+ +
+ + ); +} diff --git a/src/app/(headerless)/login/index.scss b/src/app/login/index.scss similarity index 100% rename from src/app/(headerless)/login/index.scss rename to src/app/login/index.scss diff --git a/src/app/(headerless)/login/page.tsx b/src/app/login/page.tsx similarity index 100% rename from src/app/(headerless)/login/page.tsx rename to src/app/login/page.tsx diff --git a/src/app/(header)/my/_components/ModalRemindWay/ModalRemindWay.tsx b/src/app/my/_components/ModalRemindWay/ModalRemindWay.tsx similarity index 100% rename from src/app/(header)/my/_components/ModalRemindWay/ModalRemindWay.tsx rename to src/app/my/_components/ModalRemindWay/ModalRemindWay.tsx diff --git a/src/app/(header)/my/_components/ModalRemindWay/index.scss b/src/app/my/_components/ModalRemindWay/index.scss similarity index 100% rename from src/app/(header)/my/_components/ModalRemindWay/index.scss rename to src/app/my/_components/ModalRemindWay/index.scss diff --git a/src/app/(header)/my/error.tsx b/src/app/my/error.tsx similarity index 100% rename from src/app/(header)/my/error.tsx rename to src/app/my/error.tsx diff --git a/src/app/my/hooks/useMyPage.tsx b/src/app/my/hooks/useMyPage.tsx new file mode 100644 index 00000000..4697e886 --- /dev/null +++ b/src/app/my/hooks/useMyPage.tsx @@ -0,0 +1,143 @@ +import { deleteUsers } from '@/apis/client/deleteUsers'; +import { ajajaToast } from '@/components/Toaster/customToast'; +import { KAKAO_LOGOUT_URL } from '@/constants/login'; +import { QUERY_KEY } from '@/constants/queryKey'; +import { useGetUserInformationQuery } from '@/hooks/apis/useGetUserInformationQuery'; +import { usePutUserReceiveMutation } from '@/hooks/apis/usePutUserReceiveMutation'; +import { usePostUsersRefreshMutation } from '@/hooks/apis/useRefreshNicknameMutation'; +import { ReceiveType } from '@/types/apis/users/GetUserInformation'; +import { useQueryClient } from '@tanstack/react-query'; +import { deleteCookie } from 'cookies-next'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; + +export default function useMyPage() { + const queryClient = useQueryClient(); + const { userInformation } = useGetUserInformationQuery(); + const { refreshNickname } = usePostUsersRefreshMutation(); + const { nickname, remindEmail, defaultEmail, receiveType, emailVerified } = + userInformation; + const { changeReceiveType, isChangeReceiveTypePending } = + usePutUserReceiveMutation(); + const [isOpenEmailModal, setIsOpenEmailModal] = useState(false); + const [isOpenLogOutModal, setIsOpenLogOutModal] = useState(false); + const [isOpenWithdrawalModal, setIsOpenWithdrawalModal] = + useState(false); + const [isOpenRemindWayModal, setIsOpenRemindWayModal] = + useState(false); + const router = useRouter(); + const handleChangeNickName = () => { + refreshNickname(undefined, { + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: [QUERY_KEY.USER_INFORMATION], + }); + ajajaToast.success('닉네임이 변경되었습니다.'); + }, + onError: () => { + ajajaToast.error('변경 실패, 다시 시도해주세요.'); + }, + }); + }; + const handleGoEmailVerification = () => { + setIsOpenEmailModal(true); + }; + const handleGORemindWay = () => { + setIsOpenRemindWayModal(true); + }; + const handleCloseEmailVerificationModal = () => { + setIsOpenEmailModal(false); + }; + const handleLogOut = () => { + setIsOpenLogOutModal(true); + }; + + const handleRealLogOut = async () => { + router.push(KAKAO_LOGOUT_URL); + }; + const handleCloseLogOutModal = () => { + setIsOpenLogOutModal(false); + }; + const handleWithdrawal = () => { + setIsOpenWithdrawalModal(true); + }; + const handleRealWithdrawal = () => { + deleteUsers().then(() => { + deleteCookie('auth'); + router.push('/login'); + ajajaToast.success('회원탈퇴에 성공했습니다.'); + }); + }; + const handleCloseWithdrawalModal = () => { + setIsOpenWithdrawalModal(false); + }; + const handleSetVerifiedEmail = () => { + Promise.all([ + queryClient.invalidateQueries({ + queryKey: [QUERY_KEY.USER_INFORMATION], + }), + queryClient.invalidateQueries({ queryKey: [QUERY_KEY.MY_PLANS] }), + ]); + }; + + const handleChangeReceiveType = (checked: ReceiveType) => { + if (checked === receiveType) { + ajajaToast.error('기존과 다른 방식을 선택해주세요.'); + return; + } + changeReceiveType(checked, { + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: [QUERY_KEY.USER_INFORMATION], + }); + ajajaToast.success('리마인드방식이 변경되었습니다.'); + }, + onError: () => { + ajajaToast.error('변경 실패, 다시 시도해주세요.'); + }, + }); + }; + + const createRemindWayText = () => { + if (receiveType === 'both') { + return ( + <> + 이메일과{' '} + 카카오톡 + + ); + } + return ( + + {receiveType === 'email' ? '이메일' : '카카오톡'} + + ); + }; + const remindWay = createRemindWayText(); + return { + receiveType, + nickname, + remindEmail, + defaultEmail, + emailVerified, + isChangeReceiveTypePending, + isOpenEmailModal, + isOpenLogOutModal, + isOpenRemindWayModal, + isOpenWithdrawalModal, + handleChangeNickName, + handleChangeReceiveType, + handleCloseEmailVerificationModal, + handleCloseLogOutModal, + handleCloseWithdrawalModal, + handleGORemindWay, + handleGoEmailVerification, + handleLogOut, + handleRealLogOut, + handleRealWithdrawal, + handleSetVerifiedEmail, + handleWithdrawal, + remindWay, + setIsOpenRemindWayModal, + }; +} diff --git a/src/app/(header)/my/index.scss b/src/app/my/index.scss similarity index 100% rename from src/app/(header)/my/index.scss rename to src/app/my/index.scss diff --git a/src/app/(header)/my/page.tsx b/src/app/my/page.tsx similarity index 56% rename from src/app/(header)/my/page.tsx rename to src/app/my/page.tsx index 9b16503d..c1982682 100644 --- a/src/app/(header)/my/page.tsx +++ b/src/app/my/page.tsx @@ -1,6 +1,5 @@ 'use client'; -import { deleteUsers } from '@/apis/client/deleteUsers'; import { Button, Icon, @@ -8,123 +7,39 @@ import { ModalBasic, ModalVerification, } from '@/components'; -import { ajajaToast } from '@/components/Toaster/customToast'; -import { KAKAO_LOGOUT_URL } from '@/constants/login'; -import { QUERY_KEY } from '@/constants/queryKey'; -import { useGetUserInformationQuery } from '@/hooks/apis/useGetUserInformationQuery'; -import { usePutUserReceiveMutation } from '@/hooks/apis/usePutUserReceiveMutation'; -import { usePostUsersRefreshMutation } from '@/hooks/apis/useRefreshNicknameMutation'; -import { ReceiveType } from '@/types/apis/users/GetUserInformation'; -import { useQueryClient } from '@tanstack/react-query'; -import { deleteCookie } from 'cookies-next'; import Link from 'next/link'; -import { useRouter } from 'next/navigation'; -import { useState } from 'react'; import ModalRemindWay from './_components/ModalRemindWay/ModalRemindWay'; +import useMyPage from './hooks/useMyPage'; import './index.scss'; export default function MyPage() { - const queryClient = useQueryClient(); - const { userInformation } = useGetUserInformationQuery(); - const { refreshNickname } = usePostUsersRefreshMutation(); - const { nickname, remindEmail, defaultEmail, receiveType, emailVerified } = - userInformation; - const { changeReceiveType, isChangeReceiveTypePending } = - usePutUserReceiveMutation(); - const [isOpenEmailModal, setIsOpenEmailModal] = useState(false); - const [isOpenLogOutModal, setIsOpenLogOutModal] = useState(false); - const [isOpenWithdrawalModal, setIsOpenWithdrawalModal] = - useState(false); - const [isOpenRemindWayModal, setIsOpenRemindWayModal] = - useState(false); - const router = useRouter(); - const handleChangeNickName = () => { - refreshNickname(undefined, { - onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: [QUERY_KEY.USER_INFORMATION], - }); - ajajaToast.success('닉네임이 변경되었습니다.'); - }, - onError: () => { - ajajaToast.error('변경 실패, 다시 시도해주세요.'); - }, - }); - }; - const handleGoEmailVerification = () => { - setIsOpenEmailModal(true); - }; - const handleGORemindWay = () => { - setIsOpenRemindWayModal(true); - }; - const handleCloseEmailVerificationModal = () => { - setIsOpenEmailModal(false); - }; - const handleLogOut = () => { - setIsOpenLogOutModal(true); - }; + const { + receiveType, + nickname, + remindEmail, + defaultEmail, + emailVerified, + isChangeReceiveTypePending, + isOpenEmailModal, + isOpenLogOutModal, + isOpenRemindWayModal, + isOpenWithdrawalModal, + remindWay, + handleChangeNickName, + handleChangeReceiveType, + handleCloseEmailVerificationModal, + handleCloseLogOutModal, + handleCloseWithdrawalModal, + handleGORemindWay, + handleGoEmailVerification, + handleLogOut, + handleRealLogOut, + handleRealWithdrawal, + handleSetVerifiedEmail, + handleWithdrawal, + setIsOpenRemindWayModal, + } = useMyPage(); - const handleRealLogOut = async () => { - router.push(KAKAO_LOGOUT_URL); - }; - const handleCloseLogOutModal = () => { - setIsOpenLogOutModal(false); - }; - const handleWithdrawal = () => { - setIsOpenWithdrawalModal(true); - }; - const handleRealWithdrawal = () => { - deleteUsers().then(() => { - deleteCookie('auth'); - router.push('/login'); - ajajaToast.success('회원탈퇴에 성공했습니다.'); - }); - }; - const handleCloseWithdrawalModal = () => { - setIsOpenWithdrawalModal(false); - }; - const handleSetVerifiedEmail = () => { - Promise.all([ - queryClient.invalidateQueries({ - queryKey: [QUERY_KEY.USER_INFORMATION], - }), - queryClient.invalidateQueries({ queryKey: [QUERY_KEY.MY_PLANS] }), - ]); - }; - - const handleChangeReceiveType = (checked: ReceiveType) => { - if (checked === receiveType) { - ajajaToast.error('기존과 다른 방식을 선택해주세요.'); - return; - } - changeReceiveType(checked, { - onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: [QUERY_KEY.USER_INFORMATION], - }); - ajajaToast.success('리마인드방식이 변경되었습니다.'); - }, - onError: () => { - ajajaToast.error('변경 실패, 다시 시도해주세요.'); - }, - }); - }; - - const remindWay = () => { - if (receiveType === 'both') { - return ( - <> - 이메일과{' '} - 카카오톡 - - ); - } - return ( - - {receiveType === 'email' ? '이메일' : '카카오톡'} - - ); - }; return ( <>
@@ -184,7 +99,7 @@ export default function MyPage() { 리마인드 및 응원 메시지
- {remindWay()}을 통해서 리마인드 및 응원 메시지를 받고 있어요 + {remindWay}을 통해서 리마인드 및 응원 메시지를 받고 있어요
+ + + + +
+
+ )} +
+ {isDeletePlanModalOpen && ( + + + 정말 해당 계획을 삭제하시겠습니까 ? + + + )} + + ); +} diff --git a/src/app/(header)/plans/edit/[planId]/error.tsx b/src/app/plans/edit/[planId]/error.tsx similarity index 100% rename from src/app/(header)/plans/edit/[planId]/error.tsx rename to src/app/plans/edit/[planId]/error.tsx diff --git a/src/app/plans/edit/[planId]/hooks/usePlanEditPage.tsx b/src/app/plans/edit/[planId]/hooks/usePlanEditPage.tsx new file mode 100644 index 00000000..a07a85a1 --- /dev/null +++ b/src/app/plans/edit/[planId]/hooks/usePlanEditPage.tsx @@ -0,0 +1,62 @@ +import { ajajaToast } from '@/components/Toaster/customToast'; +import { useEditPlanMutation } from '@/hooks/apis/useEditPlanMutation'; +import { useGetPlanQuery } from '@/hooks/apis/useGetPlanQuery'; +import { useWritablePlan } from '@/hooks/useWritablePlan'; +import { useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; + +export default function usePlanEditPage(planId: string) { + const router = useRouter(); + const { plan: planData } = useGetPlanQuery(Number(planId), true); + const { mutate: editPlan } = useEditPlanMutation(Number(planId)); + const isMyPlan = planData.writer.owner; + + useEffect(() => { + if (!isMyPlan) { + router.replace('/home'); + } + }, [isMyPlan, router]); + const { + nextTextAreaRef, + planContent, + handleAddTag, + handleChangeCanAjaja, + handleChangeDescription, + handleChangeIsPublic, + handleChangeTitle, + handleRemoveTag, + handleChangeIconNumber, + } = useWritablePlan(planData); + const [isSelectIconModalOpen, setIsSelectIconModalOpen] = useState(false); + + const handleEditPlan = () => { + editPlan( + { planId: Number(planId), planData: planContent }, + { + onError: () => { + ajajaToast.error('수정에 실패했습니다.'); + }, + onSuccess: () => { + router.replace(`/plans/${planId}`); + }, + }, + ); + }; + + return { + planId, + nextTextAreaRef, + isSelectIconModalOpen, + planContent, + planData, + setIsSelectIconModalOpen, + handleAddTag, + handleChangeCanAjaja, + handleChangeDescription, + handleChangeIconNumber, + handleChangeIsPublic, + handleChangeTitle, + handleEditPlan, + handleRemoveTag, + }; +} diff --git a/src/app/(header)/plans/edit/[planId]/index.scss b/src/app/plans/edit/[planId]/index.scss similarity index 100% rename from src/app/(header)/plans/edit/[planId]/index.scss rename to src/app/plans/edit/[planId]/index.scss diff --git a/src/app/(header)/plans/edit/[planId]/page.tsx b/src/app/plans/edit/[planId]/page.tsx similarity index 81% rename from src/app/(header)/plans/edit/[planId]/page.tsx rename to src/app/plans/edit/[planId]/page.tsx index ee14e6b4..fe643469 100644 --- a/src/app/(header)/plans/edit/[planId]/page.tsx +++ b/src/app/plans/edit/[planId]/page.tsx @@ -4,64 +4,37 @@ import { AjajaButton, Button, DeletableTag, + HelpButton, IconSwitchButton, Modal, ModalSelectIcon, PlanInput, + TagInput, } from '@/components'; -import HelpButton from '@/components/HelpButton/HelpButton'; -import TagInput from '@/components/TagInput/TagInput'; -import { ajajaToast } from '@/components/Toaster/customToast'; import { planIcons } from '@/constants/planIcons'; -import { useEditPlanMutation } from '@/hooks/apis/useEditPlanMutation'; -import { useGetPlanQuery } from '@/hooks/apis/useGetPlanQuery'; -import { useWritablePlan } from '@/hooks/useWritablePlan'; import classNames from 'classnames'; import Image from 'next/image'; import Link from 'next/link'; -import { useRouter } from 'next/navigation'; -import { useEffect, useState } from 'react'; +import usePlanEditPage from './hooks/usePlanEditPage'; import './index.scss'; export default function EditPage({ params }: { params: { planId: string } }) { - const { planId } = params; - const router = useRouter(); - const { plan: planData } = useGetPlanQuery(Number(planId), true); - const { mutate: editPlan } = useEditPlanMutation(Number(planId)); - const isMyPlan = planData.writer.owner; - //TODO: 권한설정 여기서? - useEffect(() => { - if (!isMyPlan) { - router.replace('/home'); - } - }, [isMyPlan, router]); const { + planId, nextTextAreaRef, + isSelectIconModalOpen, planContent, + planData, + setIsSelectIconModalOpen, handleAddTag, handleChangeCanAjaja, handleChangeDescription, + handleChangeIconNumber, handleChangeIsPublic, handleChangeTitle, + handleEditPlan, handleRemoveTag, - handleChangeIconNumber, - } = useWritablePlan(planData); - const [isSelectIconModalOpen, setIsSelectIconModalOpen] = useState(false); - - const handleEditPlan = () => { - // TODO: - editPlan( - { planId: Number(planId), planData: planContent }, - { - onError: () => { - ajajaToast.error('수정에 실패했습니다.'); - }, - onSuccess: () => { - router.replace(`/plans/${planId}`); - }, - }, - ); - }; + } = usePlanEditPage(params.planId); return (
diff --git a/src/app/(header)/reminds/[planId]/error.tsx b/src/app/reminds/[planId]/error.tsx similarity index 100% rename from src/app/(header)/reminds/[planId]/error.tsx rename to src/app/reminds/[planId]/error.tsx diff --git a/src/app/(header)/reminds/[planId]/index.scss b/src/app/reminds/[planId]/index.scss similarity index 100% rename from src/app/(header)/reminds/[planId]/index.scss rename to src/app/reminds/[planId]/index.scss diff --git a/src/app/(header)/reminds/[planId]/page.tsx b/src/app/reminds/[planId]/page.tsx similarity index 100% rename from src/app/(header)/reminds/[planId]/page.tsx rename to src/app/reminds/[planId]/page.tsx diff --git a/src/app/(header)/reminds/edit/[planId]/_hooks/useEditRemindPage.ts b/src/app/reminds/edit/[planId]/_hooks/useEditRemindPage.ts similarity index 96% rename from src/app/(header)/reminds/edit/[planId]/_hooks/useEditRemindPage.ts rename to src/app/reminds/edit/[planId]/_hooks/useEditRemindPage.ts index a6d70d13..ae55d14f 100644 --- a/src/app/(header)/reminds/edit/[planId]/_hooks/useEditRemindPage.ts +++ b/src/app/reminds/edit/[planId]/_hooks/useEditRemindPage.ts @@ -1,5 +1,5 @@ import { SESSION_STORAGE_KEY } from '@/constants'; -import { RemindData } from '@/types/Remind'; +import { RemindData } from '@/types'; import { changeRemindTimeToNumber } from '@/utils/changeRemindTimeToNumber'; import { useState } from 'react'; diff --git a/src/app/(header)/reminds/edit/[planId]/error.tsx b/src/app/reminds/edit/[planId]/error.tsx similarity index 100% rename from src/app/(header)/reminds/edit/[planId]/error.tsx rename to src/app/reminds/edit/[planId]/error.tsx diff --git a/src/app/(header)/reminds/edit/[planId]/index.scss b/src/app/reminds/edit/[planId]/index.scss similarity index 100% rename from src/app/(header)/reminds/edit/[planId]/index.scss rename to src/app/reminds/edit/[planId]/index.scss diff --git a/src/app/(header)/reminds/edit/[planId]/page.tsx b/src/app/reminds/edit/[planId]/page.tsx similarity index 98% rename from src/app/(header)/reminds/edit/[planId]/page.tsx rename to src/app/reminds/edit/[planId]/page.tsx index 88b3a4f9..88879189 100644 --- a/src/app/(header)/reminds/edit/[planId]/page.tsx +++ b/src/app/reminds/edit/[planId]/page.tsx @@ -10,8 +10,8 @@ import { ajajaToast } from '@/components/Toaster/customToast'; import { EDIT_REMIND_STEP_TITLE, SESSION_STORAGE_KEY } from '@/constants'; import { useEditRemindMutation } from '@/hooks/apis/useEditRemindMutation'; import { useGetRemindQuery } from '@/hooks/apis/useGetRemindQuery'; -import { RemindItemType, RemindOptionType } from '@/types/Remind'; -import { EditRemindData } from '@/types/apis/plan/EditRemind'; +import { RemindItemType, RemindOptionType } from '@/types'; +import { EditRemindData } from '@/types/apis'; import { changeRemindTimeToString } from '@/utils/changeRemindTimeToString'; import { checkIsSeason } from '@/utils/checkIsSeason'; import { decideRemindDate } from '@/utils/decideRemindDate'; diff --git a/src/components/CreatePlanContent/CreatePlanContent.tsx b/src/components/CreatePlanContent/CreatePlanContent.tsx index 9ce7052e..046bc395 100644 --- a/src/components/CreatePlanContent/CreatePlanContent.tsx +++ b/src/components/CreatePlanContent/CreatePlanContent.tsx @@ -1,12 +1,12 @@ 'use client'; +import { HelpButton } from '@/components'; import { INPUT_MAX_LENGTH, SESSION_STORAGE_KEY } from '@/constants'; -import { PlanContentType } from '@/types/Plan'; +import { useSessionStorage } from '@/hooks/useSessionStorage'; +import { PlanContentType } from '@/types'; import classNames from 'classnames'; import { useEffect, useRef } from 'react'; import { DeletableTag, IconSwitchButton, PlanInput, TagInput } from '..'; -import HelpButton from '../HelpButton/HelpButton'; -import { useSessionStorage } from './../../hooks/useSessionStorage'; import './index.scss'; interface CreatePlanContentProps { diff --git a/src/components/CreatePlanIcon/CreatePlanIcon.tsx b/src/components/CreatePlanIcon/CreatePlanIcon.tsx index 5b67b47d..f84e1a67 100644 --- a/src/components/CreatePlanIcon/CreatePlanIcon.tsx +++ b/src/components/CreatePlanIcon/CreatePlanIcon.tsx @@ -1,11 +1,11 @@ 'use client'; +import { CreatePlanIconExample, Modal, ModalSelectIcon } from '@/components'; import { SESSION_STORAGE_KEY, planIcons } from '@/constants'; +import { useSessionStorage } from '@/hooks/useSessionStorage'; import classNames from 'classnames'; import Image from 'next/image'; import { useEffect, useState } from 'react'; -import { CreatePlanIconExample, Modal, ModalSelectIcon } from '..'; -import { useSessionStorage } from './../../hooks/useSessionStorage'; import './index.scss'; interface CreatePlanIconProps { diff --git a/src/components/CreatePlanRemindDate/CreatePlanRemindDate.tsx b/src/components/CreatePlanRemindDate/CreatePlanRemindDate.tsx index ef010e97..f842b7a1 100644 --- a/src/components/CreatePlanRemindDate/CreatePlanRemindDate.tsx +++ b/src/components/CreatePlanRemindDate/CreatePlanRemindDate.tsx @@ -9,7 +9,7 @@ import { TOTAL_PERIOD_OPTIONS, } from '@/constants'; import { useSessionStorage } from '@/hooks/useSessionStorage'; -import { RemindOptionType } from '@/types/Remind'; +import { RemindOptionType } from '@/types'; import classNames from 'classnames'; import React, { useCallback, useEffect, useMemo } from 'react'; import './index.scss'; diff --git a/src/components/CreatePlanRemindMessage/CreatePlanRemindMessage.tsx b/src/components/CreatePlanRemindMessage/CreatePlanRemindMessage.tsx index 2c7fd781..424b766e 100644 --- a/src/components/CreatePlanRemindMessage/CreatePlanRemindMessage.tsx +++ b/src/components/CreatePlanRemindMessage/CreatePlanRemindMessage.tsx @@ -1,12 +1,11 @@ 'use client'; +import { ModalSendRemindExample, WritableRemindItem } from '@/components'; import { SESSION_STORAGE_KEY } from '@/constants'; import { useSessionStorage } from '@/hooks/useSessionStorage'; -import { RemindItemType } from '@/types/Remind'; +import { RemindItemType } from '@/types'; import classNames from 'classnames'; import React, { useCallback, useEffect, useState } from 'react'; -import { WritableRemindItem } from '..'; -import ModalSendRemindExample from '../ModalSendRemindExample/ModalSendRemindExample'; import './index.scss'; interface CreatePlanRemindMessageProps { diff --git a/src/components/ModalContinueCreate/ModalContinueCreate.tsx b/src/components/ModalContinueCreate/ModalContinueCreate.tsx index af7c31be..f3aba9b4 100644 --- a/src/components/ModalContinueCreate/ModalContinueCreate.tsx +++ b/src/components/ModalContinueCreate/ModalContinueCreate.tsx @@ -1,9 +1,9 @@ 'use client'; +import { Button, Modal } from '@/components'; import { useModalClose } from '@/hooks/useModalClose'; import classNames from 'classnames'; import React, { useRef } from 'react'; -import { Button, Modal } from '..'; import './index.scss'; interface ModalContinueCreateProps { diff --git a/src/components/ModalFixRemindDate/ModalFixRemindDate.tsx b/src/components/ModalFixRemindDate/ModalFixRemindDate.tsx index 2fa11d68..0f5442dd 100644 --- a/src/components/ModalFixRemindDate/ModalFixRemindDate.tsx +++ b/src/components/ModalFixRemindDate/ModalFixRemindDate.tsx @@ -1,6 +1,6 @@ +import { Modal, ModalBasic } from '@/components'; import classNames from 'classnames'; import React from 'react'; -import { Modal, ModalBasic } from '..'; import './index.scss'; interface ModalFixRemindDateProps { diff --git a/src/components/ModalSelectIcon/ModalSelectIcon.tsx b/src/components/ModalSelectIcon/ModalSelectIcon.tsx index 39e8f687..34e95314 100644 --- a/src/components/ModalSelectIcon/ModalSelectIcon.tsx +++ b/src/components/ModalSelectIcon/ModalSelectIcon.tsx @@ -1,6 +1,6 @@ 'use client'; -import { planIcons } from '@/constants/planIcons'; +import { planIcons } from '@/constants'; import { useModalClose } from '@/hooks/useModalClose'; import classNames from 'classnames'; import Image from 'next/image'; diff --git a/src/components/ReadOnlyPlan/ReadOnlyPlan.tsx b/src/components/ReadOnlyPlan/ReadOnlyPlan.tsx index e2eb8c3d..6dcf6df3 100644 --- a/src/components/ReadOnlyPlan/ReadOnlyPlan.tsx +++ b/src/components/ReadOnlyPlan/ReadOnlyPlan.tsx @@ -1,11 +1,16 @@ -import { planIcons } from '@/constants/planIcons'; +import { + AjajaButton, + DebounceSwitchButton, + HelpButton, + PlanInput, + Tag, +} from '@/components'; +import { ajajaToast } from '@/components/Toaster/customToast'; +import { planIcons } from '@/constants'; import { useToggleAjajaNotificationMutation } from '@/hooks/apis/useToggleAjajaNotificationMutation'; import { useToggleIsPublicMutation } from '@/hooks/apis/useToggleIsPublicMutation'; -import { PlanData } from '@/types/apis/plan/GetPlan'; +import { PlanData } from '@/types/apis'; import Image from 'next/image'; -import { AjajaButton, DebounceSwitchButton, PlanInput, Tag } from '..'; -import HelpButton from '../HelpButton/HelpButton'; -import { ajajaToast } from '../Toaster/customToast'; import './index.scss'; interface ReadOnlyPlanProps { diff --git a/src/components/RemindItem/ReadOnlyRemindItem/ReadOnlyRemindItem.tsx b/src/components/RemindItem/ReadOnlyRemindItem/ReadOnlyRemindItem.tsx index a7c19dbd..0246a091 100644 --- a/src/components/RemindItem/ReadOnlyRemindItem/ReadOnlyRemindItem.tsx +++ b/src/components/RemindItem/ReadOnlyRemindItem/ReadOnlyRemindItem.tsx @@ -1,7 +1,7 @@ 'use client'; import { Icon, RemindInput } from '@/components'; -import { ReadOnlyRemindItemData } from '@/types/Remind'; +import { ReadOnlyRemindItemData } from '@/types'; import { checkIsSeason } from '@/utils/checkIsSeason'; import classNames from 'classnames'; import React, { useMemo, useState } from 'react'; diff --git a/src/components/RemindItem/WritableRemindItem/WritableRemindItem.tsx b/src/components/RemindItem/WritableRemindItem/WritableRemindItem.tsx index 823dca02..dad9660f 100644 --- a/src/components/RemindItem/WritableRemindItem/WritableRemindItem.tsx +++ b/src/components/RemindItem/WritableRemindItem/WritableRemindItem.tsx @@ -1,7 +1,7 @@ 'use client'; import { Icon, Modal, ModalBasic, RemindInput } from '@/components'; -import { INPUT_MAX_LENGTH } from '@/constants/userInputMaxLength'; +import { INPUT_MAX_LENGTH } from '@/constants'; import classNames from 'classnames'; import React, { useEffect, useMemo, useState } from 'react'; import './index.scss'; diff --git a/src/constants/addressRegex.ts b/src/constants/addressRegex.ts new file mode 100644 index 00000000..a1a172e2 --- /dev/null +++ b/src/constants/addressRegex.ts @@ -0,0 +1,7 @@ +export const address = { + isEdit: /^\/plans\/edit\/\d+/, + isPlan: /^\/plans\/\d+/, + isRemind: /^\/reminds\/.*$/, + isFeedback: /^\/feedback\/\d+/, + isFeedbackEvaluate: /^\/feedback\/evaluate/, +}; diff --git a/src/constants/index.ts b/src/constants/index.ts index 82c9a627..fbf3d3a6 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -21,3 +21,5 @@ export { } from '@/constants/remindOptions'; export { REMIND_TIME_TEXT } from '@/constants/remindTimeText'; export { INPUT_MAX_LENGTH } from '@/constants/userInputMaxLength'; +export { address } from '@/constants/addressRegex'; +export { options } from '@/constants/radio'; diff --git a/src/constants/radio.ts b/src/constants/radio.ts new file mode 100644 index 00000000..e8d73fe3 --- /dev/null +++ b/src/constants/radio.ts @@ -0,0 +1,9 @@ +import { Option } from '@/types'; + +export const options: Option[] = [ + { value: '100', label: '매우 잘함 (100%)' }, + { value: '75', label: '잘 함 (75%)' }, + { value: '50', label: '보통 (50%)' }, + { value: '25', label: '대체로 못함 (25%)' }, + { value: '0', label: '전혀 못함 (0%)' }, +]; diff --git a/src/hooks/apis/index.ts b/src/hooks/apis/index.ts new file mode 100644 index 00000000..6137aa7f --- /dev/null +++ b/src/hooks/apis/index.ts @@ -0,0 +1,20 @@ +export { useAllPlansQuery } from '@/hooks/apis/useAllPlansQuery'; +export { useDeletePlanMutation } from '@/hooks/apis/useDeletePlanMutation'; +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 { useGetPlanQuery } from '@/hooks/apis/useGetPlanQuery'; +export { useGetRemindQuery } from '@/hooks/apis/useGetRemindQuery'; +export { useGetUserInformationQuery } from '@/hooks/apis/useGetUserInformationQuery'; +export { usePostAjajaMutation } from '@/hooks/apis/usePostAjajaMutation'; +export { usePostFeedbacksMutation } from '@/hooks/apis/usePostFeedbacksMutation'; +export { usePostNewPlanMutation } from '@/hooks/apis/usePostNewPlanMutation'; +export { usePostRemindTest } from '@/hooks/apis/usePostRemindTest'; +export { usePostSendVerificationMutation } from '@/hooks/apis/usePostSendVerificationMutation'; +export { usePostVerifyMutation } from '@/hooks/apis/usePostVerifyMutation'; +export { usePutUserReceiveMutation } from '@/hooks/apis/usePutUserReceiveMutation'; +export { usePostUsersRefreshMutation } from '@/hooks/apis/useRefreshNicknameMutation'; +export { useToggleAjajaNotificationMutation } from '@/hooks/apis/useToggleAjajaNotificationMutation'; +export { useToggleIsPublicMutation } from '@/hooks/apis/useToggleIsPublicMutation'; +export { useToggleIsRemindableMutation } from '@/hooks/apis/useToggleIsRemindable'; diff --git a/src/hooks/index.ts b/src/hooks/index.ts new file mode 100644 index 00000000..2504672c --- /dev/null +++ b/src/hooks/index.ts @@ -0,0 +1,6 @@ +export { useDebounce } from '@/hooks/useDebounce'; +export { useIsLogIn } from '@/hooks/useIsLogIn'; +export { useModalClose } from '@/hooks/useModalClose'; +export { useSessionStorage } from '@/hooks/useSessionStorage'; +export { useThrottle } from '@/hooks/useThrottle'; +export { useWritablePlan } from '@/hooks/useWritablePlan'; diff --git a/src/types/ProgressBar.ts b/src/types/ProgressBar.ts new file mode 100644 index 00000000..41b79cad --- /dev/null +++ b/src/types/ProgressBar.ts @@ -0,0 +1,3 @@ +export type ProgressBarProps = { + percent: number; +}; diff --git a/src/types/Radio.ts b/src/types/Radio.ts new file mode 100644 index 00000000..441a5862 --- /dev/null +++ b/src/types/Radio.ts @@ -0,0 +1,9 @@ +export type EvaluateRadioProps = { + evaluateOption: number; + setEvaluateOption: React.Dispatch>; +}; + +export type Option = { + value: string; + label: string; +}; diff --git a/src/types/Tab.ts b/src/types/Tab.ts new file mode 100644 index 00000000..c2589cce --- /dev/null +++ b/src/types/Tab.ts @@ -0,0 +1,6 @@ +import { SortType } from './apis'; + +export type TabProps = { + handleSort: (condition: SortType) => void; + handleYear: (isNewYear: boolean) => void; +}; diff --git a/src/types/index.ts b/src/types/index.ts index a9bbdbfc..101ceeeb 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -12,3 +12,6 @@ export type { RemindData, } from '@/types/Remind'; export type { SvgProps } from '@/types/Svg'; +export type { TabProps } from '@/types/Tab'; +export type { ProgressBarProps } from '@/types/ProgressBar'; +export type { EvaluateRadioProps, Option } from '@/types/Radio'; diff --git a/src/utils/decideRandomIconNumber.ts b/src/utils/decideRandomIconNumber.ts deleted file mode 100644 index 019d6dd6..00000000 --- a/src/utils/decideRandomIconNumber.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const decideRandomIconNumber = () => { - return Math.floor(Math.random() * 10) + 1; -}; diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 00000000..86cedc6e --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,10 @@ +export { checkIsMyPlan } from '@/utils/checkIsMyPlan'; +export { checkIsSeason } from '@/utils/checkIsSeason'; +export { checkIsTokenExpired } from '@/utils/checkIsTokenExpired'; +export { checkThisYear } from '@/utils/checkThisYear'; +export { clearCreatePlanSessionData } from '@/utils/clearCreatePlanSessionData'; +export { currentMonth } from '@/utils/currentMonth'; +export { decideRemindDate } from '@/utils/decideRemindDate'; +export { decodeJWT } from '@/utils/decodeJWT'; +export { getSessionStorageData } from '@/utils/getSessionStorageData'; +export { getUserIdFromJWT } from '@/utils/getUserIdFromJWT';