diff --git a/src/app/activity/api/api.ts b/src/app/activity/api/api.ts new file mode 100644 index 0000000..b190fcc --- /dev/null +++ b/src/app/activity/api/api.ts @@ -0,0 +1,18 @@ +import { http } from '@/api' +import { + SelectedActivityResponse, + SeletedActivityDone, +} from '@/types/activityTypes' + +export const postSelectedData = (data: SeletedActivityDone) => { + return http.post({ + url: '/activities', + data, + }) +} + +export const patchActivityDone = (activityId: number) => { + return http.patch({ + url: `/activities/${activityId}/finish`, + }) +} diff --git a/src/app/activity/api/queries.ts b/src/app/activity/api/queries.ts new file mode 100644 index 0000000..4652e27 --- /dev/null +++ b/src/app/activity/api/queries.ts @@ -0,0 +1,17 @@ +import { useMutation } from '@tanstack/react-query' +import { SeletedActivityDone } from '@/types/activityTypes' +import { patchActivityDone, postSelectedData } from './api' + +export const usePatchActivityDone = () => { + return useMutation({ + mutationKey: ['activity-edit'], + mutationFn: (activityId: number) => patchActivityDone(activityId), + }) +} + +export const usePostSelectedData = () => { + return useMutation({ + mutationKey: ['activity-dataPost'], + mutationFn: (data: SeletedActivityDone) => postSelectedData(data), + }) +} diff --git a/src/app/activity/page.tsx b/src/app/activity/page.tsx index 33a7439..9aaf503 100644 --- a/src/app/activity/page.tsx +++ b/src/app/activity/page.tsx @@ -2,14 +2,11 @@ import { useRouter } from 'next/navigation' import { useEffect, useState, useRef } from 'react' -import Cookies from 'js-cookie' import { Button } from '@/components' import useUserInfo from '@/store/useUserInfo' -import { - SeletedActivityDone, - SelectedActivityResponse, -} from '@/types/activityTypes' +import { SeletedActivityDone } from '@/types/activityTypes' import Image from 'next/image' +import { usePatchActivityDone, usePostSelectedData } from './api/queries' export default function ActivityPage() { const router = useRouter() @@ -21,41 +18,43 @@ export default function ActivityPage() { const [elapsedTime, setElapsedTime] = useState(0) const [activityId, setActivityId] = useState(0) const [spareTimeLocal, setSpareTimeLocal] = useState() - const [accessToken, setAccessToken] = useState() // 타이머 ID를 useRef로 관리하여 리렌더링 방지 const intervalId = useRef(null) const timeoutId = useRef(null) - const activityDone = async () => { - if (localStorage.getItem('activityCompleted')) { - return - } - - try { - const activityDonePatch = await fetch( - `https://cnergy.p-e.kr/v1/activities/${activityId}/finish`, - { - method: 'PATCH', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${accessToken}`, - }, - }, - ) - - if (!activityDonePatch.ok) { - throw new Error(`HTTP error! status: ${activityDonePatch.status}`) - } - - const toJson = await activityDonePatch.json() - console.log('받은 데이터', toJson) - - localStorage.setItem('activityCompleted', 'true') - } catch (error) { - console.error('Error sending POST request:', error) - } - } + const { mutate: activityPatch } = usePatchActivityDone() + const { mutate: postSeletData } = usePostSelectedData() + + // const activityDone = async () => { + // if (localStorage.getItem('activityCompleted')) { + // return + // } + + // try { + // const activityDonePatch = await fetch( + // `https://cnergy.p-e.kr/v1/activities/${activityId}/finish`, + // { + // method: 'PATCH', + // headers: { + // 'Content-Type': 'application/json', + // Authorization: `Bearer ${accessToken}`, + // }, + // }, + // ) + + // if (!activityDonePatch.ok) { + // throw new Error(`HTTP error! status: ${activityDonePatch.status}`) + // } + + // const toJson = await activityDonePatch.json() + // console.log('받은 데이터', toJson) + + // localStorage.setItem('activityCompleted', 'true') + // } catch (error) { + // console.error('Error sending POST request:', error) + // } + // } const calculateSavedTime = (spareTime: number, elapsedMinutes: number) => { let savedTime: number = 0 @@ -82,7 +81,7 @@ export default function ActivityPage() { if (remainingTimeMsRm <= 0) { setIsTimeUp(true) - activityDone() + activityPatch(activityId) if (intervalId.current !== null) { clearInterval(intervalId.current) @@ -104,7 +103,6 @@ export default function ActivityPage() { return () => {} } - const token = Cookies.get('accessToken') const selectedActivityLocal: SeletedActivityDone = JSON.parse(getActivityData) const spareTimeInUseEffect = selectedActivityLocal.spareTime @@ -113,38 +111,43 @@ export default function ActivityPage() { const now = Date.now() const remainActivityId = localStorage.getItem('activityId') - setAccessToken(token) setSpareTimeLocal(spareTimeInUseEffect) - const postSelectData = async () => { - try { - const response = await fetch('https://cnergy.p-e.kr/v1/activities', { - method: 'POST', - body: JSON.stringify(selectedActivityLocal), - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}`, - }, - }) - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`) - } - - const { data } = await response.json() - const responseData: SelectedActivityResponse = data - console.log('받은 데이터', responseData) - - localStorage.setItem('activityId', responseData.id.toString()) - - setActivityId(responseData.id) - } catch (error) { - console.error('Error sending POST request:', error) - } - } + // const postSelectData = async () => { + // try { + // const response = await fetch('https://cnergy.p-e.kr/v1/activities', { + // method: 'POST', + // body: JSON.stringify(selectedActivityLocal), + // headers: { + // 'Content-Type': 'application/json', + // Authorization: `Bearer ${token}`, + // }, + // }) + + // if (!response.ok) { + // throw new Error(`HTTP error! status: ${response.status}`) + // } + + // const { data } = await response.json() + // const responseData: SelectedActivityResponse = data + // console.log('받은 데이터', responseData) + + // localStorage.setItem('activityId', responseData.id.toString()) + + // setActivityId(responseData.id) + // } catch (error) { + // console.error('Error sending POST request:', error) + // } + // } if (!remainActivityId) { - postSelectData() + postSeletData(selectedActivityLocal, { + onSuccess: (data) => { + const response = data.data + localStorage.setItem('activityId', response.id.toString()) + setActivityId(response.id) + }, + }) } else { setActivityId(parseInt(remainActivityId, 10)) } @@ -170,11 +173,11 @@ export default function ActivityPage() { if (elapsed >= spareTimeMs) { // 시간이 이미 지난 경우 setIsTimeUp(true) - activityDone() + activityPatch(activityId) } else { timeoutId.current = window.setTimeout(() => { setIsTimeUp(true) - activityDone() + activityPatch(activityId) }, remainingTimeMs) updateRemainingTime(startTimeValue, spareTimeMs) @@ -223,7 +226,7 @@ export default function ActivityPage() { setElapsedTime(0) } - activityDone() + activityPatch(activityId) } // 활동 종료 처리 diff --git a/src/app/archive/api/api.ts b/src/app/archive/api/api.ts new file mode 100644 index 0000000..1a74018 --- /dev/null +++ b/src/app/archive/api/api.ts @@ -0,0 +1,12 @@ +import { http } from '@/api' +import { KeywordMonthDataResponse } from '../keyword-detail/types/type' + +export const getMonthData = ( + reqyear: number, + reqmonth: number, + reqkeyword: string, +) => { + return http.get({ + url: `/activities?year=${reqyear}&month=${reqmonth}&keywordCategory=${reqkeyword}`, + }) +} diff --git a/src/app/archive/api/queries.ts b/src/app/archive/api/queries.ts index 86ad3f8..f1243d9 100644 --- a/src/app/archive/api/queries.ts +++ b/src/app/archive/api/queries.ts @@ -1,5 +1,6 @@ -import { useSuspenseQuery } from '@tanstack/react-query' +import { useQuery, useSuspenseQuery } from '@tanstack/react-query' import { getCalendarData, getKeywordsData } from '.' +import { getMonthData } from './api' export const useGetCalendarData = (year: number, month: number) => useSuspenseQuery({ @@ -14,3 +15,15 @@ export const useGetKeywordsData = (year: number, month: number) => queryFn: () => getKeywordsData(year, month), select: (data) => data.data, }) + +export const useGetKeywordMonthData = ( + year: number, + month: number, + keyword: string, +) => { + return useQuery({ + queryKey: ['keywords-month', year, month, keyword], + queryFn: () => getMonthData(year, month, keyword), + enabled: !!year && !!month && !!keyword, + }) +} diff --git a/src/app/archive/api/types.ts b/src/app/archive/api/types.ts index 9e295b3..e0e7817 100644 --- a/src/app/archive/api/types.ts +++ b/src/app/archive/api/types.ts @@ -54,3 +54,21 @@ export const categoryLabels: Record = { RELAXATION: '휴식', SOCIAL: '소셜', } + +export interface KeywordActivityData { + title: string + savedTime: number + dateOfActivity: string +} + +export interface KeyWordData { + category: Category + image: string +} + +export interface KeywordMontDataResponse { + totalSavedTimeByKeywordInMonth: number + totalActivityCountByKeywordInMonth: number + activities: KeywordActivityData[] + Keyword: KeyWordData +} diff --git a/src/app/archive/keyword-detail/page.tsx b/src/app/archive/keyword-detail/page.tsx index 8126e0a..ce0c693 100644 --- a/src/app/archive/keyword-detail/page.tsx +++ b/src/app/archive/keyword-detail/page.tsx @@ -5,13 +5,13 @@ import Image from 'next/image' import { useEffect, useState } from 'react' import { format, getMonth, getYear, parseISO } from 'date-fns' import { ko } from 'date-fns/locale' -import Cookies from 'js-cookie' import { IconLeft, Clock } from '@/components' import useUserInfo from '@/store/useUserInfo' import { useMonthTotalCount } from '@/store/monthCount' import { KeywordMonthDataResponse, MonthActivity } from './types/type' import { transKeyword } from '../components/Treemap/Treemap' import OverviewHeaderForDetail from '../components/OverviewHeaderForDetail' +import { useGetKeywordMonthData } from '../api/queries' export default function KeywordDetailPage() { const searchParams = useSearchParams() @@ -19,7 +19,7 @@ export default function KeywordDetailPage() { const { nickname } = useUserInfo().userInfo const { setMonthCount } = useMonthTotalCount() - const [accessToken, setAccessToken] = useState('') + // const [accessToken, setAccessToken] = useState('') const [currentDate, setCurrentDate] = useState(new Date()) const [keyword, setKeyword] = useState('') const [isInitialized, setIsInitialized] = useState(false) @@ -29,12 +29,17 @@ export default function KeywordDetailPage() { const [activitiesByDate, setActivitiesByDate] = useState>() + const [year, setYear] = useState(0) + const [month, setMonth] = useState(0) + + const { data, isError } = useGetKeywordMonthData(year, month, keyword) + useEffect(() => { - const token = Cookies.get('accessToken') + // const token = Cookies.get('accessToken') - if (token) { - setAccessToken(token) - } + // if (token) { + // setAccessToken(token) + // } const queryYear = searchParams.get('year') const queryMonth = searchParams.get('month') @@ -51,41 +56,48 @@ export default function KeywordDetailPage() { } }, []) - const getMonthData = async ( - reqyear: number, - reqmonth: number, - reqkeyword: string, - ) => { - try { - const response = await fetch( - `https://cnergy.p-e.kr/v1/activities?year=${reqyear}&month=${reqmonth}&keywordCategory=${reqkeyword}`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${accessToken}`, - }, - }, - ) - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`) - } - - const { data } = await response.json() - - setMonthCount(data.totalActivityCountByKeywordInMonth) - setKeywordData(data) - } catch (error) { - console.error('Error sending POST request:', error) - } - } + // const getMonthData = async ( + // reqyear: number, + // reqmonth: number, + // reqkeyword: string, + // ) => { + // try { + // const response = await fetch( + // `https://cnergy.p-e.kr/v1/activities?year=${reqyear}&month=${reqmonth}&keywordCategory=${reqkeyword}`, + // { + // method: 'GET', + // headers: { + // 'Content-Type': 'application/json', + // Authorization: `Bearer ${accessToken}`, + // }, + // }, + // ) + + // if (!response.ok) { + // throw new Error(`HTTP error! status: ${response.status}`) + // } + + // const { data } = await response.json() + + // setMonthCount(data.totalActivityCountByKeywordInMonth) + // setKeywordData(data) + // } catch (error) { + // console.error('Error sending POST request:', error) + // } + // } useEffect(() => { if (isInitialized) { - const year = getYear(currentDate) - const month = getMonth(currentDate) + 1 - getMonthData(year, month, keyword) + const nowYear = getYear(currentDate) + const nowMonth = getMonth(currentDate) + 1 + + setYear(nowYear) + setMonth(nowMonth) + + if (data && !isError) { + setMonthCount(data.data.totalActivityCountByKeywordInMonth) + setKeywordData(data.data) + } } }, [keyword, currentDate]) diff --git a/src/app/home/sg-activity/api/api.ts b/src/app/home/sg-activity/api/api.ts new file mode 100644 index 0000000..fe1d14f --- /dev/null +++ b/src/app/home/sg-activity/api/api.ts @@ -0,0 +1,10 @@ +import { http } from '@/api' +import { ActivityResponseData } from '@/types/activityTypes' +import { ActivityRecommendRequest } from '../types/types' + +export const postSuggestData = (data: ActivityRecommendRequest) => { + return http.post({ + url: 'recommendations', + data, + }) +} diff --git a/src/app/home/sg-activity/api/queries.ts b/src/app/home/sg-activity/api/queries.ts new file mode 100644 index 0000000..38e56ac --- /dev/null +++ b/src/app/home/sg-activity/api/queries.ts @@ -0,0 +1,10 @@ +import { useMutation } from '@tanstack/react-query' +import { postSuggestData } from './api' +import { ActivityRecommendRequest } from '../types/types' + +export const usePostActivity = () => { + return useMutation({ + mutationKey: ['activity-recommend'], + mutationFn: (data: ActivityRecommendRequest) => postSuggestData(data), + }) +} diff --git a/src/app/home/sg-activity/components/ChoiceSuggestions.tsx b/src/app/home/sg-activity/components/ChoiceSuggestions.tsx index f57484c..77f15e6 100644 --- a/src/app/home/sg-activity/components/ChoiceSuggestions.tsx +++ b/src/app/home/sg-activity/components/ChoiceSuggestions.tsx @@ -1,7 +1,6 @@ 'use client' import { useEffect, useState } from 'react' -import Cookies from 'js-cookie' import useUserInfo from '@/store/useUserInfo' import { useActivityStore } from '@/store/activityStore' @@ -13,11 +12,12 @@ import 'swiper/css/navigation' import 'swiper/css/pagination' import { Pagination } from 'swiper/modules' -import { ActivityData, ActivityResponse } from '@/types/activityTypes' +import { ActivityData } from '@/types/activityTypes' -import { ChoiceSuggestionProps } from '../types/types' +import { ActivityRecommendRequest, ChoiceSuggestionProps } from '../types/types' import '../styles/choicesuggestion.css' import SuggestionWait from './SuggestionWait' +import { usePostActivity } from '../api/queries' const getActiveType = (typeArr: string[]) => { if (typeArr.length >= 2) { @@ -46,12 +46,13 @@ export default function ChoiceSuggestion({ const { spareTime, activityType, keywords, address } = useActivityStore() const [responseData, setResponseData] = useState() const activeType = getActiveType(activityType) - const postData = { + const postData: ActivityRecommendRequest = { spareTime: parseInt(spareTime, 10), activityType: activeType, keywords, ...(address && { location: address }), } + const { mutate: postActivity } = usePostActivity() useEffect(() => { setError(false) @@ -65,45 +66,59 @@ export default function ChoiceSuggestion({ postData.spareTime = quickStart.spareTime } - const fetchData = async () => { - // console.log('보내는 데이터 확인', postData) - try { - setIsSuggestLoading(true) - - const accessToken = Cookies.get('accessToken') - - const response = await fetch( - 'https://cnergy.p-e.kr/v1/recommendations', - { - method: 'POST', - body: JSON.stringify(postData), - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${accessToken}`, - }, - }, - ) - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`) - } - - const toJson: ActivityResponse = await response.json() - // console.log('받은 데이터', toJson) + // const fetchData = async () => { + // // console.log('보내는 데이터 확인', postData) + // try { + // setIsSuggestLoading(true) + + // const accessToken = Cookies.get('accessToken') + + // const response = await fetch( + // 'https://cnergy.p-e.kr/v1/recommendations', + // { + // method: 'POST', + // body: JSON.stringify(postData), + // headers: { + // 'Content-Type': 'application/json', + // Authorization: `Bearer ${accessToken}`, + // }, + // }, + // ) + + // if (!response.ok) { + // throw new Error(`HTTP error! status: ${response.status}`) + // } + + // const toJson: ActivityResponse = await response.json() + // // console.log('받은 데이터', toJson) + // const mergeArr = [ + // ...toJson.data.offlineRecommendations, + // ...toJson.data.onlineRecommendations, + // ] + // // console.log('데이터', mergeArr) + // setResponseData(mergeArr) + // } catch (error) { + // console.error('Error sending POST request:', error) + // } finally { + // setIsSuggestLoading(false) + // } + // } + + setIsSuggestLoading(true) + + postActivity(postData, { + onSuccess: (data) => { + const response = data.data + const mergeArr = [ - ...toJson.data.offlineRecommendations, - ...toJson.data.onlineRecommendations, + ...response.offlineRecommendations, + ...response.onlineRecommendations, ] - // console.log('데이터', mergeArr) + setResponseData(mergeArr) - } catch (error) { - console.error('Error sending POST request:', error) - } finally { setIsSuggestLoading(false) - } - } - - fetchData() + }, + }) return () => { setIsSuggestLoading(false) diff --git a/src/app/home/sg-activity/types/types.ts b/src/app/home/sg-activity/types/types.ts index 35b58dd..d87aa0c 100644 --- a/src/app/home/sg-activity/types/types.ts +++ b/src/app/home/sg-activity/types/types.ts @@ -35,3 +35,10 @@ export interface LocationDataType { x: string y: string } + +export interface ActivityRecommendRequest { + spareTime: number + activityType: 'OFFLINE' | 'ONLINE' | 'ONLINE_AND_OFFLINE' | '' + keywords: string[] + location?: string +}