diff --git a/src/hooks/useAxios.ts b/src/hooks/useAxios.ts
new file mode 100644
index 0000000..ac59166
--- /dev/null
+++ b/src/hooks/useAxios.ts
@@ -0,0 +1,93 @@
+import axios from 'axios'
+import { useSpinnerStore } from '@/store/spinnerStore'
+
+export const useAxios = () => {
+ const { setIsShow } = useSpinnerStore()
+
+ const axiosInstance = (url: string | null | undefined) => {
+ const baseURL = url || process.env.NEXT_PUBLIC_API_URL
+ const instance = axios.create({
+ baseURL,
+ headers: {
+ Accept: 'application/json',
+ },
+ })
+
+ instance.interceptors.request.use(
+ (config) => {
+ // console.log('🚀 ~ config:', config)
+ setIsShow(true)
+ return config
+ },
+ (error) => {
+ return Promise.reject(error)
+ },
+ )
+
+ instance.interceptors.response.use(
+ (response) => {
+ response.data = transferResponse(response)
+ setIsShow(false)
+ return response
+ },
+ (error) => {
+ // 에러 처리 로직
+ return Promise.reject(error)
+ },
+ )
+
+ return instance
+ }
+
+ // response데이터가 array, object에 따라 분기하여 키 변환
+ const transferResponse = (response: any) => {
+ if (!response.data) return response.data
+
+ // 배열인 경우 각 객체의 키를 변환
+ if (Array.isArray(response.data)) {
+ return response.data.map((item: any) => transformObjectKeys(item))
+ }
+
+ // 단일 객체인 경우
+ return transformObjectKeys(response.data)
+ }
+
+ // camel case object 반환
+ const transformObjectKeys = (obj: any): any => {
+ if (Array.isArray(obj)) {
+ return obj.map(transformObjectKeys)
+ }
+
+ if (obj !== null && typeof obj === 'object') {
+ return Object.keys(obj).reduce((acc: any, key: string) => {
+ let transformedKey = key
+
+ // Handle uppercase snake_case (e.g., USER_NAME -> userName)
+ // Handle lowercase snake_case (e.g., user_name -> userName)
+ if (/^[A-Z_]+$/.test(key) || /^[a-z_]+$/.test(key)) {
+ transformedKey = snakeToCamel(key)
+ }
+ // Handle single uppercase word (e.g., ROLE -> role)
+ else if (/^[A-Z]+$/.test(key)) {
+ transformedKey = key.toLowerCase()
+ }
+ // Preserve existing camelCase
+
+ acc[transformedKey] = transformObjectKeys(obj[key])
+ return acc
+ }, {})
+ }
+
+ return obj
+ }
+
+ const snakeToCamel = (str: string): string => {
+ return str.toLowerCase().replace(/([-_][a-z])/g, (group) => group.toUpperCase().replace('-', '').replace('_', ''))
+ }
+
+ return {
+ axiosInstance,
+ transferResponse,
+ transformObjectKeys,
+ }
+}
diff --git a/src/hooks/useSurvey.ts b/src/hooks/useSurvey.ts
index 1bfa614..6610cea 100644
--- a/src/hooks/useSurvey.ts
+++ b/src/hooks/useSurvey.ts
@@ -1,11 +1,10 @@
-import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import type { SurveyBasicInfo, SurveyDetailInfo, SurveyDetailRequest, SurveyDetailCoverRequest, SurveyRegistRequest } from '@/types/Survey'
-import { axiosInstance } from '@/libs/axios'
-import { useSurveyFilterStore } from '@/store/surveyFilterStore'
-import { queryStringFormatter } from '@/utils/common-utils'
-import { useSessionStore } from '@/store/session'
import { useMemo } from 'react'
-import { AxiosResponse } from 'axios'
+import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
+import { useSurveyFilterStore } from '@/store/surveyFilterStore'
+import { useSessionStore } from '@/store/session'
+import { useAxios } from './useAxios'
+import { queryStringFormatter } from '@/utils/common-utils'
export const requiredFields = [
{
@@ -75,6 +74,7 @@ export function useServey(id?: number): {
const queryClient = useQueryClient()
const { keyword, searchOption, isMySurvey, sort, offset } = useSurveyFilterStore()
const { session } = useSessionStore()
+ const { axiosInstance } = useAxios()
const {
data: surveyListData,
diff --git a/src/libs/axios.ts b/src/libs/axios.ts
index 0abc6ab..6007c47 100644
--- a/src/libs/axios.ts
+++ b/src/libs/axios.ts
@@ -1,3 +1,4 @@
+import { useSpinnerStore } from '@/store/spinnerStore'
import axios from 'axios'
export const axiosInstance = (url: string | null | undefined) => {
diff --git a/src/providers/EdgeProvider.tsx b/src/providers/EdgeProvider.tsx
index 77b8edd..e04f0e5 100644
--- a/src/providers/EdgeProvider.tsx
+++ b/src/providers/EdgeProvider.tsx
@@ -8,6 +8,8 @@ import { usePopupController } from '@/store/popupController'
import { useSideNavState } from '@/store/sideNavState'
import { useSessionStore } from '@/store/session'
import { tracking } from '@/libs/tracking'
+import Spinner from '@/components/ui/common/Spinner'
+import { useSpinnerStore } from '@/store/spinnerStore'
declare global {
interface Window {
@@ -28,6 +30,7 @@ export default function EdgeProvider({ children, sessionData }: EdgeProviderProp
const { reset } = useSideNavState()
const { setAlertMsg, setAlertBtn, setAlert, setAlert2, setAlert2BtnYes, setAlert2BtnNo } = usePopupController()
const { session, setSession } = useSessionStore()
+ const { isShow, setIsShow } = useSpinnerStore()
/**
* 사용자 이벤트 트래킹 처리
@@ -110,5 +113,10 @@ export default function EdgeProvider({ children, sessionData }: EdgeProviderProp
handlePageEvent(pathname)
}, [pathname])
- return <>{children}>
+ return (
+ <>
+ {children}
+ {isShow && }
+ >
+ )
}
diff --git a/src/store/spinnerStore.ts b/src/store/spinnerStore.ts
new file mode 100644
index 0000000..976382e
--- /dev/null
+++ b/src/store/spinnerStore.ts
@@ -0,0 +1,21 @@
+import { create } from 'zustand'
+
+type SpinnerState = {
+ isShow: boolean
+ setIsShow: (isShow: boolean) => void
+ resetCount: () => void
+}
+
+type InitialState = {
+ isShow: boolean
+}
+
+const initialState: InitialState = {
+ isShow: false,
+}
+
+export const useSpinnerStore = create((set) => ({
+ ...initialState,
+ setIsShow: (isShow: boolean) => set({ isShow }),
+ resetCount: () => set(initialState),
+}))