diff --git a/package-lock.json b/package-lock.json index 2a6982b..df5556c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "license": "ISC", "dependencies": { - "@tanstack/react-query": "^5.40.1", + "@tanstack/react-query": "^5.51.23", "axios": "^1.7.2", "next": "^14.2.3", "react-cookie": "^7.1.4", @@ -31,6 +31,7 @@ "@storybook/nextjs": "^8.1.6", "@storybook/react": "^8.1.6", "@storybook/test": "^8.1.6", + "@tanstack/react-query-devtools": "^5.51.23", "@types/morgan": "^1.9.9", "@types/node": "^20.14.2", "@types/react": "^18.3.3", @@ -6086,20 +6087,30 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.50.1", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.50.1.tgz", - "integrity": "sha512-lpfhKPrJlyV2DSVcQb/HuozH3Av3kws4ge22agx+lNGpFkS4vLZ7St0l3GLwlAD+bqB+qXGex3JdRKUNtMviEQ==", + "version": "5.51.21", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.51.21.tgz", + "integrity": "sha512-POQxm42IUp6n89kKWF4IZi18v3fxQWFRolvBA6phNVmA8psdfB1MvDnGacCJdS+EOX12w/CyHM62z//rHmYmvw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-devtools": { + "version": "5.51.16", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.51.16.tgz", + "integrity": "sha512-ajwuq4WnkNCMj/Hy3KR8d3RtZ6PSKc1dD2vs2T408MdjgKzQ3klVoL6zDgVO7X+5jlb5zfgcO3thh4ojPhfIaw==", + "dev": true, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tanstack/react-query": { - "version": "5.50.1", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.50.1.tgz", - "integrity": "sha512-s0DW3rVBDPReDDovUjVqItVa3R2nPfUANK9nqGvarO2DwTiY9U4EBTsqizMxItRCoGgK5apeM7D3mxlHrSKpdQ==", + "version": "5.51.23", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.51.23.tgz", + "integrity": "sha512-CfJCfX45nnVIZjQBRYYtvVMIsGgWLKLYC4xcUiYEey671n1alvTZoCBaU9B85O8mF/tx9LPyrI04A6Bs2THv4A==", "dependencies": { - "@tanstack/query-core": "5.50.1" + "@tanstack/query-core": "5.51.21" }, "funding": { "type": "github", @@ -6109,6 +6120,23 @@ "react": "^18.0.0" } }, + "node_modules/@tanstack/react-query-devtools": { + "version": "5.51.23", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.51.23.tgz", + "integrity": "sha512-XpHrdyfUPGULIyJ1K7UvhAcK+KjMJdw4NjmRjryoj3XEgfAU5qU1rz8gIFvGc3gTGT07yIseGo7GEll/ICfJfQ==", + "dev": true, + "dependencies": { + "@tanstack/query-devtools": "5.51.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "^5.51.23", + "react": "^18 || ^19" + } + }, "node_modules/@testing-library/dom": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.1.0.tgz", diff --git a/package.json b/package.json index fc7eb22..e700b99 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ }, "homepage": "https://github.com/YAPP-Github/24th-Web-Team-2-FE#readme", "dependencies": { - "@tanstack/react-query": "^5.40.1", + "@tanstack/react-query": "^5.51.23", "axios": "^1.7.2", "next": "^14.2.3", "react-cookie": "^7.1.4", @@ -46,6 +46,7 @@ "@storybook/nextjs": "^8.1.6", "@storybook/react": "^8.1.6", "@storybook/test": "^8.1.6", + "@tanstack/react-query-devtools": "^5.51.23", "@types/morgan": "^1.9.9", "@types/node": "^20.14.2", "@types/react": "^18.3.3", diff --git a/src/api/axiosInstance.ts b/src/api/axiosInstance.ts new file mode 100644 index 0000000..e6e343e --- /dev/null +++ b/src/api/axiosInstance.ts @@ -0,0 +1,5 @@ +import axios from 'axios'; + +export const axiosInstance = axios.create({ + withCredentials: true, +}); diff --git a/src/api/hooks/useInterestMutation.ts b/src/api/hooks/useInterestMutation.ts new file mode 100644 index 0000000..fafe6f5 --- /dev/null +++ b/src/api/hooks/useInterestMutation.ts @@ -0,0 +1,21 @@ +import { useMutation } from '@tanstack/react-query'; +import { axiosInstance } from '@/api/axiosInstance'; +import { AxiosError, AxiosResponse } from 'axios'; + +interface postMutationParams { + interestList: string[]; +} + +export const postMutation = ({ interestList }: postMutationParams) => { + return axiosInstance.post('/inbox/interests', { + interests: interestList.map(data => { + return { category: data }; + }), + }); +}; + +export const useInterestMutation = () => { + return useMutation({ + mutationFn: postMutation, + }); +}; diff --git a/src/api/queryClient.tsx b/src/api/queryClient.tsx new file mode 100644 index 0000000..acc7ee8 --- /dev/null +++ b/src/api/queryClient.tsx @@ -0,0 +1,25 @@ +'use client'; +import { QueryClientProvider, QueryClient } from '@tanstack/react-query'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +import { useState } from 'react'; + +export default function ReactQueryProviders({ children }: React.PropsWithChildren) { + const [client] = useState( + new QueryClient({ + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + refetchOnMount: false, + retry: 1, + }, + }, + }), + ); + + return ( + + {children} + + + ); +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index dabfc94..f3c1dfa 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,4 +1,6 @@ import type { Metadata } from 'next'; +import type { PropsWithChildren } from 'react'; +import ReactQueryProviders from '@/api/queryClient'; import '@/styles/tailwind.css'; export const metadata: Metadata = { @@ -6,14 +8,12 @@ export const metadata: Metadata = { description: 'Your Daily Insight Source', }; -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { +export default function RootLayout({ children }: Readonly) { return ( - {children} + + {children} + ); } diff --git a/src/app/onboard/interest/page.tsx b/src/app/onboard/interest/page.tsx index d0f166e..c187c1c 100644 --- a/src/app/onboard/interest/page.tsx +++ b/src/app/onboard/interest/page.tsx @@ -1,4 +1,3 @@ -import { OnboardButton } from '@/components/OnboardButton'; import { getInterestList } from '@/api/onboard'; import InterestInteraction from '@/components/PageInteraction/Onboard/InterestInteraction'; @@ -7,7 +6,40 @@ interface InterestProps { } const Interest = async ({ userName = '채현' }: InterestProps) => { - const interestList = await getInterestList(); + // const interestList = await getInterestList(); + + const interestList = [ + { + id: 'randomstring1', + interest: '시사', + desc: '세상 돌아가는', + }, + { + id: 'randomstring2', + interest: 'IT/테크', + desc: '최신 테크', + }, + { + id: 'randomstring3', + interest: '디자인', + desc: '디자인 영감', + }, + { + id: 'randomstring4', + interest: '경제', + desc: '핵심 기업', + }, + { + id: 'randomstring5', + interest: '트렌드', + desc: '글로벌 트렌드', + }, + { + id: 'randomstring6', + interest: '채용', + desc: '신규 채용', + }, + ]; return (
diff --git a/src/app/onboard/layout.tsx b/src/app/onboard/layout.tsx index b607606..de533a7 100644 --- a/src/app/onboard/layout.tsx +++ b/src/app/onboard/layout.tsx @@ -3,7 +3,6 @@ import type { Metadata } from 'next'; import '@/styles/tailwind.css'; import OnboardHeader from '@/components/Header/OnboardHeader'; import { PropsWithChildren } from 'react'; - export const metadata: Metadata = { title: 'Inspo Mail Club', description: 'TODO: FIX DESCRIPTION', diff --git a/src/components/PageInteraction/Onboard/InterestInteraction.tsx b/src/components/PageInteraction/Onboard/InterestInteraction.tsx index 840b974..568bb04 100644 --- a/src/components/PageInteraction/Onboard/InterestInteraction.tsx +++ b/src/components/PageInteraction/Onboard/InterestInteraction.tsx @@ -1,14 +1,19 @@ 'use client'; +import { useInterestMutation } from '@/api/hooks/useInterestMutation'; import { OnboardButton } from '@/components/OnboardButton'; import type { Interest } from '@/types/onboard'; import { useState } from 'react'; +import { useRouter } from 'next/navigation'; interface InterestInteractionProps { interestList: Interest[]; } const InterestInteraction = ({ interestList }: InterestInteractionProps) => { const [selectedCategory, setSelectedCategory] = useState([]); + const router = useRouter(); + + const interestMutation = useInterestMutation(); const handleCategoryClick = (category: string) => { if (selectedCategory.includes(category)) { @@ -20,7 +25,12 @@ const InterestInteraction = ({ interestList }: InterestInteractionProps) => { }; const handleConfirmBtnClick = () => { - console.log('confirm button clicked with selected category: ', selectedCategory); + interestMutation.mutate( + { interestList: selectedCategory }, + { + onSuccess: () => router.push('/onboard/emailList'), // TODO: 백엔드 개발 미완, 수정필요 + }, + ); }; return ( diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index bb8baad..bf50d1e 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -38,6 +38,9 @@ export const handlers = [ ], }); }), + http.post('/inbox/interests', () => { + return HttpResponse.json({}, { status: 201 }); + }), http.get('/auth/google', () => { const CookieHeader: HeadersInit = new Headers(); diff --git a/src/network/index.tsx b/src/network/index.tsx index 45c2ec0..6e85af5 100644 --- a/src/network/index.tsx +++ b/src/network/index.tsx @@ -4,7 +4,7 @@ import { cookies } from 'next/headers'; const SSR_API_ORIGIN = process.env.NEXT_PUBLIC_API_MOCK === 'enabled' ? process.env.NEXT_PUBLIC_MOCK_URL : process.env.NEXT_PUBLIC_API_URL; -const fetchWrapper = async ({ method, url, body, params, header }: any) => { +const fetchWrapper = async ({ method, url, body, params }: any) => { const config: AxiosRequestConfig = { baseURL: SSR_API_ORIGIN,