From 919c15b31483de4e2a615d05c3d47d4c81f99799 Mon Sep 17 00:00:00 2001 From: sincerity developer <85999976+jisung24@users.noreply.github.com> Date: Tue, 28 Nov 2023 15:36:57 +0900 Subject: [PATCH 01/22] =?UTF-8?q?fix:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EB=A1=9C=EC=BB=AC=EC=A3=BC=EC=86=8C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20(#206)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/api/mypage/myPageApi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/api/mypage/myPageApi.ts b/src/libs/api/mypage/myPageApi.ts index 854698a6..c2097527 100644 --- a/src/libs/api/mypage/myPageApi.ts +++ b/src/libs/api/mypage/myPageApi.ts @@ -3,7 +3,7 @@ import request from '@/libs/api' export const myPageApi = async (): Promise => { try { - const req = await request.get('http://3.114.43.57:8080/members') + const req = await request.get('/members') return req.data } catch { throw new Error('cannot get api from myPage') From 527c9e9396b65b78c8e4e2d67cd0130c1a445927 Mon Sep 17 00:00:00 2001 From: sincerity developer <85999976+jisung24@users.noreply.github.com> Date: Tue, 28 Nov 2023 16:44:06 +0900 Subject: [PATCH 02/22] =?UTF-8?q?fix:=20=EB=A7=88=EC=9A=B4=ED=8A=B8?= =?UTF-8?q?=EC=8B=9C=20=EB=82=98=ED=83=80=EB=82=98=EB=8A=94=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=A0=9C=EA=B1=B0=20(#224)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/store/likeacademyAtom.tsx | 8 +-- src/pages/likeAcademy/LikeAcademy.tsx | 76 +++++++++++---------------- 2 files changed, 35 insertions(+), 49 deletions(-) diff --git a/src/libs/store/likeacademyAtom.tsx b/src/libs/store/likeacademyAtom.tsx index 80da2dce..9f49eba2 100644 --- a/src/libs/store/likeacademyAtom.tsx +++ b/src/libs/store/likeacademyAtom.tsx @@ -2,9 +2,7 @@ import { atom } from 'jotai' import { GetLikeAcademyResponse } from '@/libs/api/likeacademy/LikeAcademyType' const initialLikeAcademyAtom: GetLikeAcademyResponse = { - likeAcademyInfos: [ - { likeId: 0, academyId: 0, academyName: '', expectedFee: 0 } - ], + likeAcademyInfos: [], totalFee: 0 } @@ -14,3 +12,7 @@ const checkGroup: boolean[] = [] export const totalAtom = atom(total) export const checkGroupAtom = atom(checkGroup) export const likeAcademyAtom = atom(initialLikeAcademyAtom) + +// onChange로직 다시 +// 아이 이름 입력 시 특수문자 => 에러메시지 거르자 +// 디폴트 이미지 => diff --git a/src/pages/likeAcademy/LikeAcademy.tsx b/src/pages/likeAcademy/LikeAcademy.tsx index b9b7fa9b..63bf9489 100644 --- a/src/pages/likeAcademy/LikeAcademy.tsx +++ b/src/pages/likeAcademy/LikeAcademy.tsx @@ -50,54 +50,38 @@ const LikeAcademy = () => {
- {likeAcademies?.likeAcademyInfos && - likeAcademies.likeAcademyInfos?.map( - ({ likeId, academyId, academyName, expectedFee }, index) => ( -
  • - onClick(index)} + {likeAcademies.likeAcademyInfos.length > 0 + ? likeAcademies.likeAcademyInfos.map( + ({ academyId, academyName, expectedFee }, index) => ( +
  • -
    -

    {academyName}

    -

    - {'예상 교육비'} - - {expectedFee} - {'원'} - -

    -
    - { - deleteLikeAcademyApi(likeId) - setLikeAcademy((prev) => ({ - likeAcademyInfos: - prev?.likeAcademyInfos?.filter((_, i) => i !== index) || - [], - totalFee: prev?.totalFee || 0 - })) - setCheckGroup( - (prevCheckGroup) => - prevCheckGroup?.filter((_, i) => i !== index) || [] - ) - }} - /> -
  • + 'relative list-none h-[100px] px-[12px] py-[20px] border-b-[1px]' + }> + onClick(index)} + className={ + 'absolute top-[50%] translate-y-[-50%] cursor-pointer' + } + /> +
    +

    {academyName}

    +

    + {'예상 교육비'} + + {expectedFee} + {'원'} + +

    +
    + + ) ) - )} + : ''}
    Date: Tue, 28 Nov 2023 17:48:39 +0900 Subject: [PATCH 03/22] =?UTF-8?q?feat:=20silder=20=EB=B0=94=20=EC=A0=9C?= =?UTF-8?q?=EC=9E=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/progressBar/ProgressBar.tsx | 4 - src/components/common/slider/Slider.tsx | 153 +++++++++++++----- 2 files changed, 110 insertions(+), 47 deletions(-) diff --git a/src/components/common/progressBar/ProgressBar.tsx b/src/components/common/progressBar/ProgressBar.tsx index 0c74a880..34a89681 100644 --- a/src/components/common/progressBar/ProgressBar.tsx +++ b/src/components/common/progressBar/ProgressBar.tsx @@ -9,10 +9,6 @@ const ProgressBar = ({ fullStepNum: number step: number }) => { - if (step > fullStepNum) { - alert(`스텝은 전체 스텝 개수인 ${fullStepNum}보다 클 수 없습니다.`) - return <> - } const progressBarWidth = (step / fullStepNum) * 100 return (
    diff --git a/src/components/common/slider/Slider.tsx b/src/components/common/slider/Slider.tsx index 701d0bd5..a69712ec 100644 --- a/src/components/common/slider/Slider.tsx +++ b/src/components/common/slider/Slider.tsx @@ -1,49 +1,116 @@ import { useState } from 'react' -const Silder = ({ - minNum = 0, - maxNum = 100_000 -}: { - minNum: number - maxNum: number -}) => { - const [value, setValue] = useState(1) +const Silder = ({ onChange }: { onChange: () => void }) => { + const [value, setValue] = useState(0) + const parseAcademyFee = (value: number) => { + switch (value) { + case 0: { + return '0 ~ 10만원' + } + case 100_000: { + return '10만원 ~ 20만원' + } + case 200_000: { + return '20만원 ~ 30만원' + } + case 300_000: { + return '30만원 ~ 40만원' + } + case 400_000: { + return '40만원 ~ 50만원' + } + case 500_000: { + return '50만원 ~ 60만원' + } + case 600_000: { + return '60만원 ~ 70만원' + } + case 700_000: { + return '70만원 이상' + } + } + } return ( -
    -
    {value}
    -
    -
    -
    -
    -
    - { - const newValue = Number.parseInt(e.target.value, 10) - setValue(newValue) - }} - /> +
    +
    + {parseAcademyFee(value)} +
    +
    +
    +
    {'0'}
    +
    +
    + {'20'} +
    +
    + {'10'} +
    +
    +
    + {'30'} +
    +
    +
    + {'40'} +
    +
    +
    + {'50'} +
    +
    +
    + {'60'} +
    +
    + {'70~'} +
    + { + const newValue = Number.parseInt(e.target.value, 10) + setValue(newValue * 1000) + }} + /> +
    ) } From 84f12d9e60c8365adf0028627d98bf2c40e53cc2 Mon Sep 17 00:00:00 2001 From: sincerity developer <85999976+jisung24@users.noreply.github.com> Date: Tue, 28 Nov 2023 18:44:28 +0900 Subject: [PATCH 04/22] =?UTF-8?q?likeAcademy=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#229)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 마운트시 나타나는 데이터 제거 * fix: get요청 확인 * fix: 머지 미반영 코드 추가 * fix: likeAcademy page 수정 * fix: 안 쓰는 변수 제거 --- src/pages/likeAcademy/LikeAcademy.tsx | 89 +++++++++++++++++---------- src/pages/setting/SettingPage.tsx | 2 +- 2 files changed, 56 insertions(+), 35 deletions(-) diff --git a/src/pages/likeAcademy/LikeAcademy.tsx b/src/pages/likeAcademy/LikeAcademy.tsx index 63bf9489..bdb4e61f 100644 --- a/src/pages/likeAcademy/LikeAcademy.tsx +++ b/src/pages/likeAcademy/LikeAcademy.tsx @@ -1,11 +1,13 @@ import { useEffect } from 'react' import { useAtom } from 'jotai' +import SettingPage from '../setting/SettingPage' import Icon from '@/components/common/icon/Icon' import Spacing from '@/components/common/spacing/Spacing' import { getLikeAcademyApi, deleteLikeAcademyApi } from '@/libs/api/likeacademy/LikeAcademyApi' +import useSidebar from '@/libs/hooks/useSidebar' import { totalAtom, checkGroupAtom, @@ -16,7 +18,7 @@ const LikeAcademy = () => { const [total, setTotal] = useAtom(totalAtom) const [likeAcademies, setLikeAcademy] = useAtom(likeAcademyAtom) const [checkGroup, setCheckGroup] = useAtom(checkGroupAtom) - + const { toggleOpen } = useSidebar() const onClick = (index: number) => { setCheckGroup((prevCheckGroup) => { const newCheckGroup = [...prevCheckGroup] @@ -47,39 +49,59 @@ const LikeAcademy = () => { } }, [checkGroup]) return ( -
    +
    -
    - {likeAcademies.likeAcademyInfos.length > 0 - ? likeAcademies.likeAcademyInfos.map( - ({ academyId, academyName, expectedFee }, index) => ( -
  • +
    + {likeAcademies?.likeAcademyInfos && + likeAcademies.likeAcademyInfos?.map( + ({ likeId, academyId, academyName, expectedFee }, index) => ( +
  • + onClick(index)} className={ - 'relative list-none h-[100px] px-[12px] py-[20px] border-b-[1px]' - }> - onClick(index)} - className={ - 'absolute top-[50%] translate-y-[-50%] cursor-pointer' - } - /> -
    -

    {academyName}

    -

    - {'예상 교육비'} - - {expectedFee} - {'원'} - -

    -
    -
  • - ) + 'absolute top-[50%] translate-y-[-50%] cursor-pointer' + } + /> +
    +

    {academyName}

    +

    + {'예상 교육비'} + + {expectedFee === 0 + ? '알 수 없습니다' + : expectedFee + '원'} + +

    +
    + { + deleteLikeAcademyApi(likeId) + setLikeAcademy((prev) => ({ + likeAcademyInfos: + prev?.likeAcademyInfos?.filter((_, i) => i !== index) || + [], + totalFee: prev?.totalFee || 0 + })) + setCheckGroup( + (prevCheckGroup) => + prevCheckGroup?.filter((_, i) => i !== index) || [] + ) + }} + /> + ) : ''} @@ -89,8 +111,7 @@ const LikeAcademy = () => { }> {'예상 교육금액'} - {total} - {'원'} + {total === 0 ? '알 수 없습니다' : total + '원'}
    diff --git a/src/pages/setting/SettingPage.tsx b/src/pages/setting/SettingPage.tsx index 3f17606e..62bf3a06 100644 --- a/src/pages/setting/SettingPage.tsx +++ b/src/pages/setting/SettingPage.tsx @@ -16,7 +16,7 @@ const SettingPage = ({ isOpen }: SettingPage) => { {() => (
    Date: Wed, 29 Nov 2023 00:37:13 +0900 Subject: [PATCH 05/22] =?UTF-8?q?fix:=20scroll=20=EC=97=86=EC=95=A0?= =?UTF-8?q?=EA=B3=A0,=20=EC=A0=84=EC=B2=B4=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detailSchedule/DetailSchedulePage.tsx | 4 +-- src/pages/calendar/data.ts | 29 ------------------- 2 files changed, 2 insertions(+), 31 deletions(-) delete mode 100644 src/pages/calendar/data.ts diff --git a/src/pages/academy/detailSchedule/DetailSchedulePage.tsx b/src/pages/academy/detailSchedule/DetailSchedulePage.tsx index cf04596f..49db2fbe 100644 --- a/src/pages/academy/detailSchedule/DetailSchedulePage.tsx +++ b/src/pages/academy/detailSchedule/DetailSchedulePage.tsx @@ -70,8 +70,8 @@ const DetailSchedulePage = () => {
    - -
    + +
    {data?.academyInfo.address}
    diff --git a/src/pages/calendar/data.ts b/src/pages/calendar/data.ts deleted file mode 100644 index da6f9d24..00000000 --- a/src/pages/calendar/data.ts +++ /dev/null @@ -1,29 +0,0 @@ -export const DATA = { - date: '2023-10-20 목요일', - academyInfo: { - academyName: '닥스 어학원', - address: '서울 강동구 상암로 12, 202호' - }, - lessonInfo: { - lessonName: '체르니 100 타파반', - capacity: '50명', - total_fee: '300000', - lessonTimes: [ - { - startTime: '', - endTime: '', - dayOfWeek: '' - }, - { - startTime: '', - endTime: '', - dayOfWeek: '' - } - ], - periodicity: '' - }, - childrenInfos: [ - { childId: '1L', childName: '', memo: '', imageUrl: '', dashBoardId: '' }, - { childId: '2L', childName: '', memo: '', imageUrl: '', dashBoardId: '' } - ] -} From a64dd0ff8d9febf9bfdc06b4492bcbaa48e9a241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EC=84=9C=EB=A6=AC=ED=8B=B0=EC=BD=94=EB=8D=94?= <85999976+jisung24@users.noreply.github.com> Date: Wed, 29 Nov 2023 00:45:40 +0900 Subject: [PATCH 06/22] =?UTF-8?q?fix:=20=EC=95=84=EC=BD=94=EB=94=94?= =?UTF-8?q?=EC=96=B8=20=EA=B0=80=EC=9A=B4=EB=8D=B0=EC=A0=95=EB=A0=AC,=20?= =?UTF-8?q?=EB=A9=94=EB=AA=A8=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detailSchedule/DetailSchedulePage.tsx | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/src/pages/academy/detailSchedule/DetailSchedulePage.tsx b/src/pages/academy/detailSchedule/DetailSchedulePage.tsx index 49db2fbe..df868d81 100644 --- a/src/pages/academy/detailSchedule/DetailSchedulePage.tsx +++ b/src/pages/academy/detailSchedule/DetailSchedulePage.tsx @@ -76,32 +76,35 @@ const DetailSchedulePage = () => {
    -
    - } - contentHeight={100} - content={ - <> - {'정원'}} - rightElement={ - - {data?.lessonInfo.capacity + '명 정원'} - - } - /> - {'금액'}} - rightElement={ - - {data?.lessonInfo.totalFee + '원'} - - } - /> - - } - /> +
    +
    + } + contentHeight={100} + content={ + <> + {'정원'}} + rightElement={ + + {data?.lessonInfo.capacity + '명 정원'} + + } + /> + {'금액'}} + rightElement={ + + {data?.lessonInfo.totalFee + '원'} + + } + /> + + } + /> +

    {'일정 수행중인 아이'}

    @@ -126,13 +129,12 @@ const DetailSchedulePage = () => {

    {'메모'}

      {data?.childrenInfos.map(({ memo, childId }) => ( -
    • - +
    • {memo}
    • ))}
    -
    +
    - {'시설이 좋아요'} + {'시설이 좋아요 🏫'}
    - {'가격이 착해요'} + {'교육비가 저렴해요 💰'}
    - {'학습 관리가 꼼꼼해요'} + {'교육 관리가 철저해요 📝'}
    - {'선생님이 좋아요'} + {'학생에 대한 애정 가득 💓'} +
    +
    +
    +
    +
    +
    + {'등하원이 편리해요 🚌'}
    diff --git a/src/components/BottomSheet/BottomSheetHeader.tsx b/src/components/BottomSheet/BottomSheetHeader.tsx index ded7c85d..dd113c72 100644 --- a/src/components/BottomSheet/BottomSheetHeader.tsx +++ b/src/components/BottomSheet/BottomSheetHeader.tsx @@ -1,26 +1,38 @@ import { useState } from 'react' +import { useMutation } from '@tanstack/react-query' import { LikeBlank, LikeFilled } from '@/assets/icon' +import { postLike } from '@/libs/api/mapapi/mapApi.ts' const BottomSheetHeader = ({ title, - isLike + isLike, + academyId }: { title: string isLike: boolean + academyId: number }) => { + const likeMutation = useMutation({ + mutationFn: (academyId: number) => postLike({ academyId: academyId }), + onSuccess: () => { + setLiked(!liked) + } + }) + const [liked, setLiked] = useState(isLike) //TODO: 좋아요 API 로직 추가 + return (

    {title}

    {liked ? ( setLiked(!liked)} + onClick={() => likeMutation.mutate(academyId)} /> ) : ( setLiked(!liked)} + onClick={() => likeMutation.mutate(academyId)} /> )}
    diff --git a/src/components/common/bottomsheet/BottomSheet.tsx b/src/components/common/bottomsheet/BottomSheet.tsx index 3112043e..dcfcefc5 100644 --- a/src/components/common/bottomsheet/BottomSheet.tsx +++ b/src/components/common/bottomsheet/BottomSheet.tsx @@ -1,8 +1,10 @@ import { useState } from 'react' +import { useQuery } from '@tanstack/react-query' import BottomSheetContent from '@/components/BottomSheet/BottomSheetContent' import BottomSheetHeader from '@/components/BottomSheet/BottomSheetHeader' +import Loading from '@/components/Loading/Loading.tsx' import Spacing from '@/components/common/spacing/Spacing.tsx' -import { DetailAcademyResponse } from '@/libs/api/mapapi/mapApiType.ts' +import { getAcademyDetail } from '@/libs/api/mapapi/mapApi.ts' /** * @param title BottomSheet에 들어갈 Title을 입력합니다. @@ -13,15 +15,24 @@ interface BottomSheetProps { title: string address: string number: string - detailInfo: DetailAcademyResponse + academyId: number } const BottomSheet = ({ title = '학원명 입력', address, number, - detailInfo + academyId }: BottomSheetProps) => { const [expanded, setExpanded] = useState(false) + const { data: detailAcademy, isLoading } = useQuery({ + queryKey: ['academy', academyId], + queryFn: () => + getAcademyDetail({ + academyId: academyId + }), + enabled: academyId > -1 + }) + return ( <>
    -
    - - -
    + {isLoading && } + {detailAcademy && ( +
    + + +
    + )}
    ) From 91779994789542bbb048bd2aaa83d76f9de9e120 Mon Sep 17 00:00:00 2001 From: kimheeseok Date: Wed, 29 Nov 2023 11:14:58 +0900 Subject: [PATCH 09/22] =?UTF-8?q?hotfix:=20=EC=A2=8B=EC=95=84=EC=9A=94=20a?= =?UTF-8?q?pi=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20ReviewPercent=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/api/mapapi/mapApi.ts | 12 ++++++++++++ src/libs/api/mapapi/mapApiType.ts | 9 ++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/libs/api/mapapi/mapApi.ts b/src/libs/api/mapapi/mapApi.ts index 80b04c2f..b1bfbd4c 100644 --- a/src/libs/api/mapapi/mapApi.ts +++ b/src/libs/api/mapapi/mapApi.ts @@ -7,6 +7,7 @@ import { GetAcademysParams, GetLocationParam, GetTownParam, + LikeResponse, LocationResponse, ProvinceResponse, TownResponse @@ -64,3 +65,14 @@ export const getAcademyDetail = async ({ return res.data } + +export const postLike = async ({ + academyId +}: { + academyId: number +}): Promise => { + const res = await request.post(`/likes`, { + academyId: academyId + }) + return res.data +} diff --git a/src/libs/api/mapapi/mapApiType.ts b/src/libs/api/mapapi/mapApiType.ts index 65bcf8e4..06a30e39 100644 --- a/src/libs/api/mapapi/mapApiType.ts +++ b/src/libs/api/mapapi/mapApiType.ts @@ -71,6 +71,7 @@ interface ReviewPercent { cheapFeePercent: number goodManagementPercent: number lovelyTeachingPercent: number + shuttleAvailabilityCount: number } export interface DetailAcademyResponse { @@ -80,7 +81,7 @@ export interface DetailAcademyResponse { shuttleAvailability: string expectedFee: number updatedDate: string - areaOfExpertise: string + categories: string[] lessonGetResponses: { lessons: Lesson[] } @@ -108,3 +109,9 @@ export interface InfiniteScrollPage { paged: boolean unpaged: boolean } + +export interface LikeResponse { + likeId: number + memberId: number + academyId: number +} From 93c09e4090db3b60e8b2263adbca3ae4a5bad8b7 Mon Sep 17 00:00:00 2001 From: kimheeseok Date: Wed, 29 Nov 2023 11:15:45 +0900 Subject: [PATCH 10/22] =?UTF-8?q?hotfix:=20=EB=A7=B5=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EA=B2=80=EC=83=89=EB=B0=94=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=EC=A7=80=EB=8F=84=EA=B0=80=20?= =?UTF-8?q?=EB=B3=B4=EC=9D=B4=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/map/MapSearchBar.tsx | 126 +++++++++++++++++++ src/components/map/NaverMap.tsx | 124 ++++++++----------- src/pages/map/MapPage.tsx | 182 ++++------------------------ 3 files changed, 199 insertions(+), 233 deletions(-) create mode 100644 src/components/map/MapSearchBar.tsx diff --git a/src/components/map/MapSearchBar.tsx b/src/components/map/MapSearchBar.tsx new file mode 100644 index 00000000..95d3b728 --- /dev/null +++ b/src/components/map/MapSearchBar.tsx @@ -0,0 +1,126 @@ +import { useEffect, useState } from 'react' +import { useInView } from 'react-intersection-observer' +import { useNavigate } from 'react-router-dom' +import { useQuery } from '@tanstack/react-query' +import Icon from '@/components/common/icon/Icon.tsx' +import Input from '@/components/common/inputbox/input/Input.tsx' +import { getAcademiesSearchResult } from '@/libs/api/academy/AcademyApi.ts' +import { SearchAcademiesResponse } from '@/libs/api/mapapi/mapApiType.ts' +import { useDebounce } from '@/libs/hooks/useDebounce.ts' + +const MapSearchBar = () => { + const navigate = useNavigate() + const [searchValue, setSearchValue] = useState('') + const [page, setPage] = useState(0) + const debounceValue = useDebounce(searchValue, 300) + const [searchList, setSearchList] = useState([]) + + const { ref, inView } = useInView({ + threshold: 1 + }) + + const { data: searchData } = useQuery({ + queryKey: ['searchData', debounceValue, page], + queryFn: () => getAcademiesSearchResult(debounceValue, page), + enabled: debounceValue !== '' + }) + + useEffect(() => { + if (searchData && page === 0) { + // 검색어만 바뀌었을때 + setSearchList([...searchData.content]) + } else if (searchData && page > 0) { + // 페이지가 바뀌었을때 + setSearchList((prevList) => [...prevList, ...searchData.content]) + } else { + // debounceValue가 ''일때 + setSearchList([]) + } + }, [searchData, page, debounceValue]) + + const isLast = searchData?.last || false + const updatePage = () => { + setPage(page + 1) + } + + //검색어가 바뀔때마다 페이지도 0으로 맞춰 api를 호출 + const updateSearchValue = (value: string) => { + setSearchValue(value) + setPage(0) + } + + const observer = ( +
    + ) + + useEffect(() => { + if (isLast) { + return + } else if (inView) { + updatePage() + } + }, [inView]) + + return ( +
    +
    + { + updateSearchValue(e.target.value) + }} + /> +
    0 + ? 'rounded-lg border-blue-350 border mb-4 mt-2' + : '' + }`}> + {searchList.length > 0 && ( +
    + {searchList.map((data, index) => ( +
    { + console.log(data) + }}> + +
    +
    + {data.academyName} +
    +
    + {data.address} +
    +
    +
    + ))} + {observer} +
    + )} +
    +
    +
    navigate('/map/filter')}> + + {'필터'} +
    +
    + ) +} + +export default MapSearchBar diff --git a/src/components/map/NaverMap.tsx b/src/components/map/NaverMap.tsx index 85fde460..cb848f73 100644 --- a/src/components/map/NaverMap.tsx +++ b/src/components/map/NaverMap.tsx @@ -1,17 +1,14 @@ import { useCallback, useEffect, useRef, useState } from 'react' -import { useQuery } from '@tanstack/react-query' +import { useNavigate } from 'react-router-dom' import { useAtom } from 'jotai/index' -import { SetLocationProps } from '../../types/mapPage.ts' -import BottomSheet from '@/components/common/bottomsheet/BottomSheet.tsx' import Icon from '@/components/common/icon/Icon.tsx' import { DefaultMapOption, initSelectAcademy, Marker } from '@/components/map/constants.ts' -import { getAcademyDetail } from '@/libs/api/mapapi/mapApi.ts' import { Academy } from '@/libs/api/mapapi/mapApiType.ts' -import { selectAcademyAtom } from '@/libs/store/mapInfoAtom.ts' +import { mapInfoAtom, selectAcademyAtom } from '@/libs/store/mapInfoAtom.ts' import throttle from '@/libs/utils/throttle.ts' /** @@ -19,45 +16,16 @@ import throttle from '@/libs/utils/throttle.ts' * * **/ interface NaverMapProps { - latitude: number - longitude: number academyList: Academy[] - setLocation: ({ latitude, longitude }: SetLocationProps) => void - searchAcademy: number //나중에 제외해야합니다. } -const NaverMap = ({ - latitude, - longitude, - academyList, - setLocation, - searchAcademy -}: NaverMapProps) => { +const NaverMap = ({ academyList }: NaverMapProps) => { const mapRef = useRef(null) + const markerRef = useRef([]) + const [mapInfo, setMapInfo] = useAtom(mapInfoAtom) const [selectAcademy, setSelectAcademy] = useAtom(selectAcademyAtom) const [isNewLocation, setIsNewLocation] = useState(false) - - useEffect(() => { - if (searchAcademy > -1) { - setSelectAcademy((prev) => ({ - ...prev, - isBottomSheet: true - })) - console.log(selectAcademy) - } - }, [searchAcademy]) - - const { data: detailAcademy } = useQuery({ - queryKey: ['academy', selectAcademy], - queryFn: () => - getAcademyDetail({ - academyId: - selectAcademy.academy.academyId > -1 - ? selectAcademy.academy.academyId - : searchAcademy - }), - enabled: selectAcademy.academy.academyId > -1 || searchAcademy > -1 - }) + const navigate = useNavigate() const currentLocation = useCallback(() => { if (!navigator.geolocation || !mapRef.current) { @@ -68,13 +36,12 @@ const NaverMap = ({ (position) => { const { latitude, longitude } = position.coords const center = new naver.maps.LatLng(latitude, longitude) - console.log(center) mapRef.current?.panTo(center, { duration: 500, easing: 'easeOutCubic' }) }, - () => console.log('test'), + () => navigate('/'), { enableHighAccuracy: false, timeout: 1000 @@ -84,17 +51,54 @@ const NaverMap = ({ const updateLocation = useCallback(() => { const location = mapRef.current?.getCenter() - setLocation({ + createMap({ latitude: location?.y as number, longitude: location?.x as number }) + + setMapInfo((prev) => ({ + ...prev, + latitude: location?.y as number, + longitude: location?.x as number + })) + setIsNewLocation(false) }, []) + const createMap = ({ + latitude, + longitude + }: { + latitude: number + longitude: number + }) => { + const center: naver.maps.LatLng = new naver.maps.LatLng(latitude, longitude) + const naverMapOption = { + center: center, + ...DefaultMapOption + } + + mapRef.current = new naver.maps.Map('map', naverMapOption) + + naver.maps.Event.addListener(mapRef.current, 'click', () => + setSelectAcademy({ + isBottomSheet: false, + academy: initSelectAcademy.academy + }) + ) + + naver.maps.Event.addListener( + mapRef.current, + 'dragend', + throttle(() => { + setIsNewLocation(true) + }, 100) + ) + } + useEffect(() => { if (mapRef.current) { academyList.map((data) => { - // console.log(Marker({ value: data.academyName, select: false })) const isSelected = data.academyId === selectAcademy.academy.academyId const marker = new naver.maps.Marker({ position: new naver.maps.LatLng(data.latitude, data.longitude), @@ -103,7 +107,7 @@ const NaverMap = ({ content: Marker({ value: data.academyName, select: isSelected }) } }) - + markerRef.current.push(marker) naver.maps.Event.addListener(marker, 'click', () => { setSelectAcademy((prev) => ({ isBottomSheet: !isSelected, @@ -118,30 +122,8 @@ const NaverMap = ({ }, [academyList, selectAcademy]) useEffect(() => { - const center: naver.maps.LatLng = new naver.maps.LatLng(latitude, longitude) - const naverMapOption = { - center: center, - ...DefaultMapOption - } - - if (!mapRef.current) { - mapRef.current = new naver.maps.Map('map', naverMapOption) - } - - naver.maps.Event.addListener(mapRef.current, 'click', () => - setSelectAcademy({ - isBottomSheet: false, - academy: initSelectAcademy.academy - }) - ) - - naver.maps.Event.addListener( - mapRef.current, - 'dragend', - throttle(() => { - setIsNewLocation(true) - }, 100) - ) + const { latitude, longitude } = mapInfo + createMap({ latitude: latitude, longitude: longitude }) }, []) return ( @@ -164,14 +146,6 @@ const NaverMap = ({ )} - {selectAcademy.isBottomSheet && detailAcademy && ( - - )}
    ) } diff --git a/src/pages/map/MapPage.tsx b/src/pages/map/MapPage.tsx index f6ad993b..38f5b3c8 100644 --- a/src/pages/map/MapPage.tsx +++ b/src/pages/map/MapPage.tsx @@ -1,84 +1,20 @@ -import { useEffect, useState } from 'react' -import { useInView } from 'react-intersection-observer' -import { useLocation, useNavigate } from 'react-router-dom' +import { useLocation } from 'react-router-dom' import { useQuery } from '@tanstack/react-query' import { useAtom } from 'jotai/index' -import { SetLocationProps } from '../../types/mapPage.ts' -import SettingPage from '../setting/SettingPage.tsx' -import Icon from '@/components/common/icon/Icon.tsx' -import Input from '@/components/common/inputbox/input/Input.tsx' +import BottomSheet from '@/components/common/bottomsheet/BottomSheet.tsx' import Spacing from '@/components/common/spacing/Spacing.tsx' +import MapSearchBar from '@/components/map/MapSearchBar.tsx' import NaverMap from '@/components/map/NaverMap.tsx' -import { getAcademiesSearchResult } from '@/libs/api/academy/AcademyApi.ts' import { getAcademyFilter } from '@/libs/api/filter/filterApi.ts' import { getAcademyList } from '@/libs/api/mapapi/mapApi.ts' -import { SearchAcademiesResponse } from '@/libs/api/mapapi/mapApiType.ts' -import { useDebounce } from '@/libs/hooks' -import useSidebar from '@/libs/hooks/useSidebar.tsx' -import { mapInfoAtom } from '@/libs/store/mapInfoAtom.ts' +import { mapInfoAtom, selectAcademyAtom } from '@/libs/store/mapInfoAtom.ts' const MapPage = () => { - const { ref, inView } = useInView({ - threshold: 1 - }) - const navigate = useNavigate() + const [mapInfo] = useAtom(mapInfoAtom) + const [selectAcademy] = useAtom(selectAcademyAtom) const location = useLocation() - const [searchValue, setSearchValue] = useState('') const queryString = location.search - const debounceValue = useDebounce(searchValue, 300) - const [lastPage, setLastPage] = useState(false) - const [academiesData, setAcademiesData] = useState( - [] - ) - const [page, setPage] = useState(0) - const [isinitial, setInitial] = useState(true) - const [searchAcademy, setSearchAcademy] = useState(-1) - const { toggleOpen } = useSidebar() - useEffect(() => { - if (lastPage) { - return - } else if (inView) { - fetchSearchInfiniteScroll(debounceValue, page) - } - }, [inView]) - - const fetchSearchInfiniteScroll = async ( - searchKeyword: string, - page: number - ) => { - const data = await getAcademiesSearchResult(searchKeyword, page) - setAcademiesData([...academiesData, ...data.content]) - setPage(data.number + 1) - setInitial(data.first) - setLastPage(data.last) - } - const fetchSearchResult = async (searchKeyword: string, page: number) => { - const data = await getAcademiesSearchResult(searchKeyword, page) - setAcademiesData([...data.content]) - setPage(data.number + 1) - setInitial(data.first) - setLastPage(data.last) - } - - useEffect(() => { - if (isinitial) { - fetchSearchResult(debounceValue, 0) - } - }, [debounceValue]) - - const observer = ( -
    - ) - useEffect(() => { - console.log(searchAcademy) - }) - - const [mapInfo, setMapInfo] = useAtom(mapInfoAtom) const { data: academyList } = useQuery({ queryKey: ['academyList', mapInfo.latitude, mapInfo.longitude], queryFn: () => @@ -88,102 +24,32 @@ const MapPage = () => { }), enabled: !queryString }) + const { data: academyFilterList } = useQuery({ queryKey: ['academyFilterList', queryString], queryFn: () => getAcademyFilter({ queryString: queryString }), enabled: queryString.length > 0 }) - const moveFilter = () => { - navigate('/map/filter') - } - - const setLocation = ({ latitude, longitude }: SetLocationProps) => { - setMapInfo((prev) => ({ - ...prev, - latitude, - longitude - })) - } - return ( -
    - -
    - -
    -
    - { - setSearchValue(e.target.value) - }} - /> -
    0 - ? 'rounded-lg border-blue-350 border mb-4 mt-2' - : '' - }`}> - {academiesData.length > 0 && ( -
    - {academiesData.map((data, index) => ( -
    { - setSearchAcademy(data.academyId) - console.log(data) - }}> - -
    { - setAcademiesData([]) - }}> -
    - {data.academyName} -
    -
    - {data.address} -
    -
    -
    - ))} - {observer} -
    - )} -
    -
    -
    - - {'필터'} -
    -
    - + + + + {selectAcademy.isBottomSheet && ( + -
    + )}
    ) } From cce1582dd598b40376938dbbcfffc356d502bb70 Mon Sep 17 00:00:00 2001 From: kimheeseok Date: Wed, 29 Nov 2023 11:17:43 +0900 Subject: [PATCH 11/22] =?UTF-8?q?hotfix:=20=EC=8A=A4=ED=86=A0=EB=A6=AC?= =?UTF-8?q?=EB=B6=81=20=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bottomsheet/BottomSheet.stories.tsx | 29 +------------------ 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/src/components/common/bottomsheet/BottomSheet.stories.tsx b/src/components/common/bottomsheet/BottomSheet.stories.tsx index 58266fea..c3b4a455 100644 --- a/src/components/common/bottomsheet/BottomSheet.stories.tsx +++ b/src/components/common/bottomsheet/BottomSheet.stories.tsx @@ -23,34 +23,7 @@ export const Default: Story = { title={args.title} address={'주소'} number={'전화번호'} - detailInfo={{ - academyName: 'test', - contact: 'test', - address: 'test', - shuttleAvailability: 'test', - expectedFee: 0, - updatedDate: '2023-11-16', - areaOfExpertise: 'test', - lessonGetResponses: { - lessons: [ - { - lessonId: 0, - subject: 'test', - capacity: 0, - duration: 'test', - totalFee: 0 - } - ] - }, - reviewPercentGetResponse: { - kindnessPercent: 0, - goodFacilityPercent: 0, - cheapFeePercent: 0, - goodManagementPercent: 0, - lovelyTeachingPercent: 0 - }, - isLiked: false - }} + academyId={0} /> ) } From 375165692e3afd8b69878505a84714781d452e2c Mon Sep 17 00:00:00 2001 From: kimheeseok Date: Wed, 29 Nov 2023 12:14:11 +0900 Subject: [PATCH 12/22] =?UTF-8?q?hotfix:=20=EA=B2=80=EC=83=89=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=ED=81=B4=EB=A6=AD=EC=8B=9C=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=ED=9B=84=20=EB=A7=88=EC=BB=A4=20=ED=91=9C=EC=8B=9C=EB=90=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/map/MapSearchBar.tsx | 12 ++++-- src/components/map/NaverMap.tsx | 59 ++++++++++++++++++++++++++++- src/libs/api/mapapi/mapApiType.ts | 9 +++++ src/libs/store/mapInfoAtom.ts | 9 +++++ src/pages/map/MapPage.tsx | 14 ++++++- 5 files changed, 96 insertions(+), 7 deletions(-) diff --git a/src/components/map/MapSearchBar.tsx b/src/components/map/MapSearchBar.tsx index 95d3b728..f9060d50 100644 --- a/src/components/map/MapSearchBar.tsx +++ b/src/components/map/MapSearchBar.tsx @@ -2,11 +2,13 @@ import { useEffect, useState } from 'react' import { useInView } from 'react-intersection-observer' import { useNavigate } from 'react-router-dom' import { useQuery } from '@tanstack/react-query' +import { useAtom } from 'jotai' import Icon from '@/components/common/icon/Icon.tsx' import Input from '@/components/common/inputbox/input/Input.tsx' import { getAcademiesSearchResult } from '@/libs/api/academy/AcademyApi.ts' import { SearchAcademiesResponse } from '@/libs/api/mapapi/mapApiType.ts' import { useDebounce } from '@/libs/hooks/useDebounce.ts' +import { selectSearchAcademyAtom } from '@/libs/store/mapInfoAtom.ts' const MapSearchBar = () => { const navigate = useNavigate() @@ -14,6 +16,8 @@ const MapSearchBar = () => { const [page, setPage] = useState(0) const debounceValue = useDebounce(searchValue, 300) const [searchList, setSearchList] = useState([]) + const [_, setSelectValue] = useAtom(selectSearchAcademyAtom) + const [isHidden, setHidden] = useState(false) const { ref, inView } = useInView({ threshold: 1 @@ -46,6 +50,7 @@ const MapSearchBar = () => { //검색어가 바뀔때마다 페이지도 0으로 맞춰 api를 호출 const updateSearchValue = (value: string) => { setSearchValue(value) + setHidden(true) setPage(0) } @@ -78,11 +83,11 @@ const MapSearchBar = () => { />
    0 + searchList.length > 0 && isHidden ? 'rounded-lg border-blue-350 border mb-4 mt-2' : '' }`}> - {searchList.length > 0 && ( + {isHidden && searchList.length > 0 && (
    {searchList.map((data, index) => (
    { } key={index} onClick={() => { - console.log(data) + setSelectValue(data) + setHidden(false) }}>
    { const markerRef = useRef([]) const [mapInfo, setMapInfo] = useAtom(mapInfoAtom) const [selectAcademy, setSelectAcademy] = useAtom(selectAcademyAtom) + const [selectValue, _] = useAtom(selectSearchAcademyAtom) const [isNewLocation, setIsNewLocation] = useState(false) const navigate = useNavigate() @@ -124,7 +129,57 @@ const NaverMap = ({ academyList }: NaverMapProps) => { useEffect(() => { const { latitude, longitude } = mapInfo createMap({ latitude: latitude, longitude: longitude }) - }, []) + if (selectValue.academyId > -1) { + const marker = new naver.maps.Marker({ + position: new naver.maps.LatLng( + selectValue.latitude, + selectValue.longitude + ), + map: mapRef.current as naver.maps.Map, + icon: { + content: Marker({ value: selectValue.academyName, select: true }) + } + }) + markerRef.current = [marker] + naver.maps.Event.addListener(marker, 'click', () => { + setSelectAcademy(() => ({ + isBottomSheet: true, + academy: { + academyId: selectValue.academyId, + academyName: selectValue.academyName, + address: selectValue.address, + contact: '', + areaOfExpertise: '', + latitude: selectValue.latitude, + longitude: selectValue.longitude + } + })) + }) + + setSelectAcademy(() => ({ + isBottomSheet: true, + academy: { + academyId: selectValue.academyId, + academyName: selectValue.academyName, + address: selectValue.address, + contact: '', + areaOfExpertise: '', + latitude: selectValue.latitude, + longitude: selectValue.longitude + } + })) + } + }, [mapInfo]) + + useEffect(() => { + if (selectValue.academyId > -1) { + setMapInfo((prev) => ({ + ...prev, + longitude: selectValue.longitude, + latitude: selectValue.latitude + })) + } + }, [selectValue]) return (
    diff --git a/src/libs/api/mapapi/mapApiType.ts b/src/libs/api/mapapi/mapApiType.ts index 06a30e39..d82e2096 100644 --- a/src/libs/api/mapapi/mapApiType.ts +++ b/src/libs/api/mapapi/mapApiType.ts @@ -49,6 +49,15 @@ export interface Academy { longitude: number } +export interface SearchAcademy { + academyId: number + academyName: string + address: string + areaOfExpertise: string + latitude: number + longitude: number +} + export interface AcademyResponse { academiesByLocationResponse: Academy[] } diff --git a/src/libs/store/mapInfoAtom.ts b/src/libs/store/mapInfoAtom.ts index 60bd0a30..478cfdd6 100644 --- a/src/libs/store/mapInfoAtom.ts +++ b/src/libs/store/mapInfoAtom.ts @@ -1,6 +1,7 @@ import { atom } from 'jotai' import { MapInfoAtomType } from '../../types/selectcity.ts' import { InitSelectAcademyType } from '@/components/map/naverMapType.ts' +import { SearchAcademiesResponse } from '@/libs/api/mapapi/mapApiType.ts' export const mapInfoAtom = atom({ selectProvince: '', @@ -22,3 +23,11 @@ export const selectAcademyAtom = atom({ longitude: -1 } }) + +export const selectSearchAcademyAtom = atom({ + academyId: -1, + academyName: '', + address: '', + latitude: -1, + longitude: -1 +}) diff --git a/src/pages/map/MapPage.tsx b/src/pages/map/MapPage.tsx index 38f5b3c8..6efbc167 100644 --- a/src/pages/map/MapPage.tsx +++ b/src/pages/map/MapPage.tsx @@ -1,3 +1,4 @@ +import { useEffect } from 'react' import { useLocation } from 'react-router-dom' import { useQuery } from '@tanstack/react-query' import { useAtom } from 'jotai/index' @@ -7,11 +8,16 @@ import MapSearchBar from '@/components/map/MapSearchBar.tsx' import NaverMap from '@/components/map/NaverMap.tsx' import { getAcademyFilter } from '@/libs/api/filter/filterApi.ts' import { getAcademyList } from '@/libs/api/mapapi/mapApi.ts' -import { mapInfoAtom, selectAcademyAtom } from '@/libs/store/mapInfoAtom.ts' +import { + mapInfoAtom, + selectAcademyAtom, + selectSearchAcademyAtom +} from '@/libs/store/mapInfoAtom.ts' const MapPage = () => { const [mapInfo] = useAtom(mapInfoAtom) const [selectAcademy] = useAtom(selectAcademyAtom) + const [selectValue] = useAtom(selectSearchAcademyAtom) const location = useLocation() const queryString = location.search @@ -22,7 +28,7 @@ const MapPage = () => { latitude: mapInfo.latitude, longitude: mapInfo.longitude }), - enabled: !queryString + enabled: !queryString && selectValue.academyId === -1 }) const { data: academyFilterList } = useQuery({ @@ -31,6 +37,10 @@ const MapPage = () => { enabled: queryString.length > 0 }) + useEffect(() => { + console.log(selectAcademy) + }, [selectAcademy]) + return (
    From d37a9235543f3f3048474306d2472979ae6cbc58 Mon Sep 17 00:00:00 2001 From: Eugene Kim <67894159+eugene028@users.noreply.github.com> Date: Wed, 29 Nov 2023 14:15:47 +0900 Subject: [PATCH 13/22] =?UTF-8?q?feat:=20toast=20ui=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20(#230)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 2 +- src/components/common/header/Header.tsx | 3 --- src/components/common/toast/index.tsx | 4 ++-- src/components/layout/Layout.tsx | 3 +++ src/components/review/ReviewBottomSheet.tsx | 8 +++++-- src/libs/api/index.ts | 7 +++++- src/pages/academy/AcademyDashboard.tsx | 13 ++++++++-- .../academy/academyDetail/AcademySetting.tsx | 23 ++++++++++++++---- src/pages/academy/addSchedule/index.tsx | 5 +++- src/pages/academy/editAcademy/index.tsx | 5 +++- src/pages/home/HomePage.tsx | 9 +++++-- src/pages/mypage/MyPage.tsx | 24 +++++++++++++++---- src/pages/onboarding/OnbardingPage.tsx | 12 ++++++++-- src/pages/schedule/new/index.tsx | 12 ++++++---- 14 files changed, 101 insertions(+), 29 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 74b06dac..44fde67e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,7 @@ import './styles/index.css' - import { RouterProvider } from 'react-router-dom' import { router } from './routes' + function App() { return } diff --git a/src/components/common/header/Header.tsx b/src/components/common/header/Header.tsx index b619079d..45dea6c0 100644 --- a/src/components/common/header/Header.tsx +++ b/src/components/common/header/Header.tsx @@ -52,9 +52,6 @@ const Header = ({
    -
    alert('알림보기!')}> - -
    diff --git a/src/components/common/toast/index.tsx b/src/components/common/toast/index.tsx index 7a23a19f..5d15f848 100644 --- a/src/components/common/toast/index.tsx +++ b/src/components/common/toast/index.tsx @@ -2,7 +2,7 @@ import { ToastContainer } from 'react-toastify' const Toast = () => { return ( { toastStyle={{ borderRadius: '12px', backgroundColor: 'white', - margin: '6px' + margin: '10px' }} bodyStyle={{ color: 'ccc', lineHeight: 1.5 }} /> diff --git a/src/components/layout/Layout.tsx b/src/components/layout/Layout.tsx index a612165d..c29b8cad 100644 --- a/src/components/layout/Layout.tsx +++ b/src/components/layout/Layout.tsx @@ -1,7 +1,9 @@ import { useEffect } from 'react' import { Outlet } from 'react-router-dom' +import useToastify from '@/libs/hooks/useToastify' const Layout = () => { + const { Toast } = useToastify() useEffect(() => { const vh = window.innerHeight * 0.01 document.documentElement.style.setProperty('--vh', `${vh}px`) @@ -17,6 +19,7 @@ const Layout = () => {
    +
    diff --git a/src/components/review/ReviewBottomSheet.tsx b/src/components/review/ReviewBottomSheet.tsx index 55512347..61505700 100644 --- a/src/components/review/ReviewBottomSheet.tsx +++ b/src/components/review/ReviewBottomSheet.tsx @@ -6,6 +6,8 @@ import Spacing from '@/components/common/spacing/Spacing' import { postReview } from '@/libs/api/review/reviewApi' import { AcademyReview } from '@/libs/api/review/reviewType' import { ReviewRequestType } from '@/libs/api/review/reviewType' +import useToastify from '@/libs/hooks/useToastify' + const ReviewBottomSheet = ({ academyTitle, academyId, @@ -15,6 +17,7 @@ const ReviewBottomSheet = ({ academyId: number setBottomSheetClose: React.Dispatch> }) => { + const { setToast } = useToastify() const [reviewState, setReviewState] = useState({ academyId: academyId, KINDNESS: false, @@ -28,7 +31,7 @@ const ReviewBottomSheet = ({ mutationFn: (reviewState: ReviewRequestType) => postReview(reviewState), onSuccess: () => { setBottomSheetClose(false) - alert('리뷰 남기기 성공!') + setToast({ comment: '리뷰를 성공적으로 남겼어요.', type: 'success' }) } }) const handleMemo = (value: keyof ReviewRequestType) => { @@ -47,7 +50,8 @@ const ReviewBottomSheet = ({ useEffect(() => { const valueAry = Object.values(reviewState) const count = valueAry.filter(Boolean).length - if (count >= 4) alert('안돼') + if (count >= 4) + setToast({ comment: '리뷰는 4개 이상 남길 수 없어요.', type: 'warning' }) }, [reviewState]) return ( <> diff --git a/src/libs/api/index.ts b/src/libs/api/index.ts index 2769448c..9e6dcfea 100644 --- a/src/libs/api/index.ts +++ b/src/libs/api/index.ts @@ -1,6 +1,7 @@ import axios from 'axios' import { logoutApi } from './autorization/logout/LogoutApi' import { refreshApi } from './autorization/refresh/refreshApi' +import useToastify from '@/libs/hooks/useToastify' const request = axios.create({ baseURL: import.meta.env.VITE_API_ENDPOINT, @@ -31,13 +32,17 @@ request.interceptors.response.use( }, async (error) => { if (error.response.status === 403) { + const { setToast } = useToastify() try { const getRefreshToken = await refreshApi() const prevRequest = error.config prevRequest.headers.Authorization = `Bearer ${getRefreshToken.appToken}` return request(prevRequest) } catch { - alert('로그인이 풀리셨습니다... 로그인을 다시 진행해주세요😁') + setToast({ + comment: '로그인을 다시 진행해주세요.', + type: 'info' + }) await logoutApi() throw new Error('failed to request refresh token') } diff --git a/src/pages/academy/AcademyDashboard.tsx b/src/pages/academy/AcademyDashboard.tsx index 0b348328..8014f570 100644 --- a/src/pages/academy/AcademyDashboard.tsx +++ b/src/pages/academy/AcademyDashboard.tsx @@ -16,6 +16,7 @@ import { patchToggleDashboardState } from '@/libs/api/dashboard/DashBoardApi' import { getAllDashboards } from '@/libs/api/dashboard/DashBoardApi' import { GetAllDashBoardResponse } from '@/libs/api/dashboard/DashBoardType' import useSidebar from '@/libs/hooks/useSidebar' +import useToastify from '@/libs/hooks/useToastify' import { childAtom } from '@/libs/store/childInfoAtom' import { getWeekday } from '@/libs/utils/weekParse' @@ -24,6 +25,7 @@ const AcademyDashboard = () => { const [dashboardData, setDashboardData] = useState( [] ) + const { setToast } = useToastify() const navigate = useNavigate() const { toggleOpen } = useSidebar() @@ -127,10 +129,17 @@ const AcademyDashboard = () => { } handleDelete={() => { if (data.isActive) { - alert('다니고 있는 학원은 삭제가 불가능합니다!') + setToast({ + comment: + '다니고 있는 학원은 삭제가 불가능해요. 먼저 미등록 상태로 변경해주세요.', + type: 'warning' + }) } else { deleteDashboardInfo(data.dashboardId) - alert('삭제 완료!') + setToast({ + comment: '삭제가 완료되었어요.', + type: 'success' + }) } }} onClick={(e) => { diff --git a/src/pages/academy/academyDetail/AcademySetting.tsx b/src/pages/academy/academyDetail/AcademySetting.tsx index 2a9b2286..c45818a2 100644 --- a/src/pages/academy/academyDetail/AcademySetting.tsx +++ b/src/pages/academy/academyDetail/AcademySetting.tsx @@ -6,8 +6,10 @@ import { deleteDashboard } from '@/libs/api/dashboard/DashBoardApi' import { patchToggleDashboardState } from '@/libs/api/dashboard/DashBoardApi' import { GetAllDashBoardResponse } from '@/libs/api/dashboard/DashBoardType' import { queryClient } from '@/libs/api/queryClient' +import useToastify from '@/libs/hooks/useToastify' const AcademySetting = ({ data }: { data: GetAllDashBoardResponse }) => { const navigate = useNavigate() + const { setToast } = useToastify() const [isbottomSheetOpen, setBottomSheetOpen] = useState(false) // eslint-disable-next-line unicorn/consistent-function-scoping const deleteDashboardInfo = async (dashboardId: number) => { @@ -45,7 +47,10 @@ const AcademySetting = ({ data }: { data: GetAllDashBoardResponse }) => { queryClient.invalidateQueries({ queryKey: ['dashboard', data.dashboardId] }) - alert('성공적으로 처리했음.') + setToast({ + comment: '학원 정보를 삭제했어요.', + type: 'success' + }) }} />
    @@ -60,7 +65,10 @@ const AcademySetting = ({ data }: { data: GetAllDashBoardResponse }) => { queryClient.invalidateQueries({ queryKey: ['dashboard', data.dashboardId] }) - alert('성공적으로 처리했음.') + setToast({ + comment: '학원을 등록했어요.', + type: 'success' + }) }} />
    diff --git a/src/pages/mypage/MyPage.tsx b/src/pages/mypage/MyPage.tsx index f4ab1414..4ab7a009 100644 --- a/src/pages/mypage/MyPage.tsx +++ b/src/pages/mypage/MyPage.tsx @@ -10,15 +10,17 @@ import Spacing from '@/components/common/spacing/Spacing' import { logoutApi } from '@/libs/api/autorization/logout/LogoutApi' import { myPageApi } from '@/libs/api/mypage/myPageApi' import useSidebar from '@/libs/hooks/useSidebar' +import useToastify from '@/libs/hooks/useToastify' import { myPageAtom } from '@/libs/store/myPageAtom' const MyPage = () => { const navigate = useNavigate() + const { setToast } = useToastify() const [myPageData, setMyPageData] = useAtom(myPageAtom) const { toggleOpen } = useSidebar() useEffect(() => { if (localStorage.getItem('token') === null) { - alert('로그인 페이지로 이동합니다!') + setToast({ comment: '로그인 페이지로 이동합니다.', type: 'info' }) navigate('/login') return } @@ -46,7 +48,10 @@ const MyPage = () => { classStyle={'w-[30px] h-[30px] cursor-pointer'} onClick={() => myPageData.childInformationResponses.length === 5 - ? alert('아이가 꽉 찼습니다!') + ? setToast({ + comment: '아이는 최대 5명까지만 입력할 수 있어요.', + type: 'warning' + }) : navigate('/onboarding') } /> @@ -83,12 +88,23 @@ const MyPage = () => { buttonType={'Plain-blue'} label={'로그아웃 하기'} className={'mb-[20px]'} - onClick={() => logoutApi()} + onClick={() => { + logoutApi() + setToast({ + comment: '로그아웃이 완료되었어요.', + type: 'success' + }) + }} />
    diff --git a/src/pages/onboarding/OnbardingPage.tsx b/src/pages/onboarding/OnbardingPage.tsx index 40637a45..a4845523 100644 --- a/src/pages/onboarding/OnbardingPage.tsx +++ b/src/pages/onboarding/OnbardingPage.tsx @@ -16,11 +16,13 @@ import { onboardingApi } from '@/libs/api/onboarding/onboardingApi' import { PostOnboardingRequest } from '@/libs/api/onboarding/onboardingType' +import useToastify from '@/libs/hooks/useToastify' import { onboardingPageDataAtom } from '@/libs/store/onboardingAtom' import { getItem, setItem } from '@/libs/utils/storage' const Onboarding = () => { const navigate = useNavigate() + const { setToast } = useToastify() const [currentPage, setCurrentPage] = useState(0) const [isError, setIsError] = useState(false) const inputRef = useRef(null) @@ -70,7 +72,10 @@ const Onboarding = () => { const cntOfChild = async () => { const children = await getChildrenInfo() if (children.length === 5) { - alert('5명이 다 차있습니다!') + setToast({ + comment: '아이는 최대 5명까지만 등록이 가능해요.', + type: 'warning' + }) navigate('/') } setCurrentPage(children.length + 2) @@ -178,7 +183,10 @@ const Onboarding = () => { inputRef.current?.value === '' || selectRef.current?.value === '' ) { - alert('값을 입력해주세요😁👍') + setToast({ + comment: '값을 빠짐없이 입력해주세요.', + type: 'warning' + }) return } // ❗️ 값을 입력하고, child버튼일 때(자식입력 필드에서 존재하는 버튼 2개 diff --git a/src/pages/schedule/new/index.tsx b/src/pages/schedule/new/index.tsx index 3d783932..60df8782 100644 --- a/src/pages/schedule/new/index.tsx +++ b/src/pages/schedule/new/index.tsx @@ -1,3 +1,4 @@ +import { useNavigate } from 'react-router-dom' import { useMutation } from '@tanstack/react-query' import { useAtom } from 'jotai' import Button from '@/components/common/button/Button' @@ -5,17 +6,20 @@ import ListRowSelect from '@/components/common/listRowSelect/ListRowSelect' import Spacing from '@/components/common/spacing/Spacing' import { postScheduleApi } from '@/libs/api/schedule/scheduleApi' import { PostScheduleType } from '@/libs/api/schedule/scheduleType' +import useToastify from '@/libs/hooks/useToastify' import { scheduleAtom } from '@/libs/store/scheduleInfo' import AddScheduleAcademy from '@/pages/schedule/new/AddScheduleAcademy' import AddScheduleMemo from '@/pages/schedule/new/AddScheduleMemo' import AddScheduleTime from '@/pages/schedule/new/AddScheduleTime' - const NewSchedule = () => { + const navigate = useNavigate() const [scheduleInfo, setScheduleInfo] = useAtom(scheduleAtom) + const { setToast } = useToastify() + const postNewScheduleMutation = useMutation({ - onSuccess: () => { - alert('일정 생성 완료!') - // navigate(`/schedule/${data.academyTimeTemplateIds}`) + onSuccess: (data) => { + setToast({ comment: '일정이 생성되었어요.', type: 'success' }) + navigate(`/schedule/${data.academyTimeTemplateIds[0]}`) }, mutationFn: (scheduleInfo: PostScheduleType) => postScheduleApi(scheduleInfo) From 612877a08e05b94edfbf7927d6c59f1c88b3b151 Mon Sep 17 00:00:00 2001 From: kimheeseok Date: Wed, 29 Nov 2023 14:42:01 +0900 Subject: [PATCH 14/22] =?UTF-8?q?hotfix:=20=ED=95=84=ED=84=B0=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/slider/Slider.stories.tsx | 2 +- src/components/common/slider/Slider.tsx | 3 ++- src/libs/store/mapFilterAtom.ts | 19 ++++++++------- src/pages/filter/FilterPage.tsx | 23 ++++++++++++------- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/components/common/slider/Slider.stories.tsx b/src/components/common/slider/Slider.stories.tsx index 188055bd..3758d8af 100644 --- a/src/components/common/slider/Slider.stories.tsx +++ b/src/components/common/slider/Slider.stories.tsx @@ -12,7 +12,7 @@ const meta: Meta = { render: function Render() { return (
    - + console.log('')} />
    ) } diff --git a/src/components/common/slider/Slider.tsx b/src/components/common/slider/Slider.tsx index a69712ec..ed7ee524 100644 --- a/src/components/common/slider/Slider.tsx +++ b/src/components/common/slider/Slider.tsx @@ -31,7 +31,7 @@ const Silder = ({ onChange }: { onChange: () => void }) => { } } return ( -
    +
    {parseAcademyFee(value)}
    @@ -107,6 +107,7 @@ const Silder = ({ onChange }: { onChange: () => void }) => { } onChange={(e) => { const newValue = Number.parseInt(e.target.value, 10) + onChange() setValue(newValue * 1000) }} /> diff --git a/src/libs/store/mapFilterAtom.ts b/src/libs/store/mapFilterAtom.ts index 45d6e8f8..bf7f95b1 100644 --- a/src/libs/store/mapFilterAtom.ts +++ b/src/libs/store/mapFilterAtom.ts @@ -2,16 +2,15 @@ import { atom } from 'jotai' const initMapFilter: SubjectList = { subjectList: [ - { title: '예능', filter: '예능(대)', color: 'default' }, - { title: '국제화', filter: '국제화', color: 'default' }, - { title: '입시', filter: '입시, 검정 및 보습', color: 'default' }, - { title: '직업기술', filter: '직업기술', color: 'default' }, - { title: '종합', filter: '종합(대)', color: 'default' }, - { title: '독서실', filter: '독서실', color: 'default' }, - { title: '기예', filter: '기예(대)', color: 'default' }, - { title: '기타', filter: '기타(대)', color: 'default' }, - { title: '인문사회', filter: '인문사회(대)', color: 'default' }, - { title: '정보', filter: '정보', color: 'default' } + { title: '수학', filter: '수학', color: 'default' }, + { title: '과학', filter: '과학', color: 'default' }, + { title: '국어', filter: '국어', color: 'default' }, + { title: '영어', filter: '영어', color: 'default' }, + { title: '컴퓨터', filter: '컴퓨터', color: 'default' }, + { title: '예체능', filter: '예체능', color: 'default' }, + { title: '외국어', filter: '외국어', color: 'default' }, + { title: '보습', filter: '보습', color: 'default' }, + { title: '기타', filter: '기타', color: 'default' } ], maxMoney: 500_000, minMoney: 1 diff --git a/src/pages/filter/FilterPage.tsx b/src/pages/filter/FilterPage.tsx index 1715f26b..f41f1313 100644 --- a/src/pages/filter/FilterPage.tsx +++ b/src/pages/filter/FilterPage.tsx @@ -3,6 +3,7 @@ import { useAtom } from 'jotai' import Button from '@/components/common/button/Button.tsx' import Label from '@/components/common/label/Label.tsx' import { LabelColorType } from '@/components/common/label/LabelType.ts' +import Slider from '@/components/common/slider/Slider.tsx' import Spacing from '@/components/common/spacing/Spacing.tsx' import { mapFilterState } from '@/libs/store/mapFilterAtom.ts' import { mapInfoAtom } from '@/libs/store/mapInfoAtom.ts' @@ -23,7 +24,7 @@ const FilterPage = () => { console.log(subjectList) let url = `/map?lat=${mapInfo.latitude}&lng=${ mapInfo.longitude - }&areaOfExpertises=${subjectList.join(',')}` + }&categories=${subjectList.join(',')}` console.log(url) if (mapFilter.minMoney > 1) { @@ -106,15 +107,21 @@ const FilterPage = () => { className={ 'flex flex-col w-full h-[260px] bg-white-0 shadow-[0_4px_4px_0_rgba(0,0,0,0.25)] mb-[10px] justify-center items-center' }> - + {'희망 금액(추정치)'} -
    -
    -
    +
    +
    {

    {'일정 수행중인 아이'}

    - {data?.childrenInfos.map( - ({ childId, childName, imageUrl, dashBoardId }) => ( -
  • navigate(`academies/${dashBoardId}/edit`)}> - -
  • - ) - )} +
    + navigate(`academies/${data?.childrenInfo.dashBoardId}/edit`) + }> + +

    {'메모'}

      - {data?.childrenInfos.map(({ memo, childId }) => ( -
    • - {memo} -
    • - ))} +
      + {data?.childrenInfo.memo} +