feat: Add globalSpinner
- 글로벌 스피너 추가 - 글로벌 스피너 on/off 기능 추가
This commit is contained in:
parent
4233958df2
commit
24dca05f75
@ -32,6 +32,7 @@
|
||||
"react-icons": "^5.3.0",
|
||||
"react-loading-skeleton": "^3.5.0",
|
||||
"react-responsive-modal": "^6.4.2",
|
||||
"react-spinners": "^0.14.1",
|
||||
"recoil": "^0.7.7",
|
||||
"sweetalert2": "^11.14.1",
|
||||
"sweetalert2-react-content": "^5.0.7",
|
||||
|
||||
@ -7,14 +7,18 @@ import { usePlan } from '@/hooks/usePlan'
|
||||
import ServerError from './error'
|
||||
|
||||
import '@/styles/common.scss'
|
||||
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
|
||||
|
||||
export const QcastContext = createContext({
|
||||
qcastState: {},
|
||||
setQcastState: () => {},
|
||||
isGlobalLoading: true,
|
||||
setIsGlobalLoading: () => {},
|
||||
})
|
||||
|
||||
export const QcastProvider = ({ children }) => {
|
||||
const [planSave, setPlanSave] = useState(false)
|
||||
const [isGlobalLoading, setIsGlobalLoading] = useState(true)
|
||||
const { currentCanvasPlan, modifiedPlans, checkUnsavedCanvasPlan } = usePlan()
|
||||
const { commonCode, findCommonCode } = useCommonCode()
|
||||
|
||||
@ -43,7 +47,12 @@ export const QcastProvider = ({ children }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<QcastContext.Provider value={{ qcastState, setQcastState }}>
|
||||
{isGlobalLoading && (
|
||||
<div className="fixed inset-0 bg-white z-50 flex items-center justify-center">
|
||||
<GlobalSpinner />
|
||||
</div>
|
||||
)}
|
||||
<QcastContext.Provider value={{ qcastState, setQcastState, isGlobalLoading, setIsGlobalLoading }}>
|
||||
<ErrorBoundary fallback={<ServerError />}>{children}</ErrorBoundary>
|
||||
</QcastContext.Provider>
|
||||
</>
|
||||
|
||||
@ -62,16 +62,16 @@ export default async function RootLayout({ children }) {
|
||||
{headerPathname === '/login' || headerPathname === '/join' ? (
|
||||
<QcastProvider>{children}</QcastProvider>
|
||||
) : (
|
||||
<div className="wrap">
|
||||
<Header userSession={sessionProps} />
|
||||
<div className="content">
|
||||
<Dimmed />
|
||||
<QcastProvider>
|
||||
<QcastProvider>
|
||||
<div className="wrap">
|
||||
<Header userSession={sessionProps} />
|
||||
<div className="content">
|
||||
<Dimmed />
|
||||
<SessionProvider useSession={sessionProps}>{children}</SessionProvider>
|
||||
</QcastProvider>
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
</QcastProvider>
|
||||
)}
|
||||
<QModal />
|
||||
<PopupManager />
|
||||
|
||||
7
src/components/common/spinner/GlobalSpinner.jsx
Normal file
7
src/components/common/spinner/GlobalSpinner.jsx
Normal file
@ -0,0 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { HashLoader } from 'react-spinners'
|
||||
|
||||
export default function GlobalSpinner() {
|
||||
return <HashLoader />
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
'use client'
|
||||
import { Fragment, useCallback, useEffect, useState } from 'react'
|
||||
import { Fragment, useCallback, useContext, useEffect, useState } from 'react'
|
||||
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
@ -17,6 +17,7 @@ import { useAxios } from '@/hooks/useAxios'
|
||||
import { globalLocaleStore } from '@/store/localeAtom'
|
||||
|
||||
import { stuffSearchState } from '@/store/stuffAtom'
|
||||
import { QcastContext } from '@/app/QcastProvider'
|
||||
|
||||
export const ToggleonMouse = (e, act, target) => {
|
||||
const listWrap = e.target.closest(target)
|
||||
@ -47,6 +48,8 @@ export default function Header(props) {
|
||||
// }
|
||||
const [selected, setSelected] = useState('')
|
||||
|
||||
const { isGlobalLoading } = useContext(QcastContext)
|
||||
|
||||
const dimmedState = useRecoilValue(dimmedStore)
|
||||
const isDimmed = dimmedState ? 'opacity-50 bg-black' : ''
|
||||
|
||||
@ -164,54 +167,56 @@ export default function Header(props) {
|
||||
}
|
||||
|
||||
return (
|
||||
!(pathName.includes('login') || pathName.includes('join') || sessionState.pwdInitYn === 'N') && (
|
||||
<header className={isDimmed}>
|
||||
<div className="header-inner">
|
||||
<div className="header-right">
|
||||
<h1 className="logo">
|
||||
<Link href={'/'}></Link>
|
||||
</h1>
|
||||
<nav>
|
||||
<ul className="nav-list ">{getMenuTemplate(menus)}</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div className="header-left">
|
||||
<div className="profile-box">
|
||||
<Link
|
||||
href="#"
|
||||
onClick={() => {
|
||||
setUserInfoModal(true)
|
||||
}}
|
||||
>
|
||||
<button className="profile">{userSession.userNm}</button>
|
||||
</Link>
|
||||
{userInfoModal && <UserInfoModal userId={sessionState.userId} userInfoModal={userInfoModal} setUserInfoModal={setUserInfoModal} />}
|
||||
<>
|
||||
{!isGlobalLoading && !(pathName.includes('login') || pathName.includes('join') || sessionState.pwdInitYn === 'N') && (
|
||||
<header className={isDimmed}>
|
||||
<div className="header-inner">
|
||||
<div className="header-right">
|
||||
<h1 className="logo">
|
||||
<Link href={'/'}></Link>
|
||||
</h1>
|
||||
<nav>
|
||||
<ul className="nav-list ">{getMenuTemplate(menus)}</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div className="sign-out-box">
|
||||
<button
|
||||
className="sign-out"
|
||||
onClick={() => {
|
||||
setStuffSearch({
|
||||
...stuffSearch,
|
||||
code: 'DELETE',
|
||||
})
|
||||
logout()
|
||||
}}
|
||||
>
|
||||
{getMessage('header.logout')}
|
||||
</button>
|
||||
</div>
|
||||
<div className="select-box">
|
||||
<QSelectBox options={SelectOptions} onChange={onChangeSelect} />
|
||||
</div>
|
||||
<div className="btn-wrap">
|
||||
<button className="btn-frame small dark" onClick={() => navPage()}>
|
||||
{getMessage('header.go')}
|
||||
</button>
|
||||
<div className="header-left">
|
||||
<div className="profile-box">
|
||||
<Link
|
||||
href="#"
|
||||
onClick={() => {
|
||||
setUserInfoModal(true)
|
||||
}}
|
||||
>
|
||||
<button className="profile">{userSession.userNm}</button>
|
||||
</Link>
|
||||
{userInfoModal && <UserInfoModal userId={sessionState.userId} userInfoModal={userInfoModal} setUserInfoModal={setUserInfoModal} />}
|
||||
</div>
|
||||
<div className="sign-out-box">
|
||||
<button
|
||||
className="sign-out"
|
||||
onClick={() => {
|
||||
setStuffSearch({
|
||||
...stuffSearch,
|
||||
code: 'DELETE',
|
||||
})
|
||||
logout()
|
||||
}}
|
||||
>
|
||||
{getMessage('header.logout')}
|
||||
</button>
|
||||
</div>
|
||||
<div className="select-box">
|
||||
<QSelectBox options={SelectOptions} onChange={onChangeSelect} />
|
||||
</div>
|
||||
<div className="btn-wrap">
|
||||
<button className="btn-frame small dark" onClick={() => navPage()}>
|
||||
{getMessage('header.go')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
</header>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useContext } from 'react'
|
||||
import { useContext, useEffect } from 'react'
|
||||
import { useAxios } from '../useAxios'
|
||||
import { SessionContext } from '@/app/SessionProvider'
|
||||
import { QcastContext } from '@/app/QcastProvider'
|
||||
@ -8,7 +8,11 @@ import { QcastContext } from '@/app/QcastProvider'
|
||||
export const useMainContentsController = () => {
|
||||
const { session } = useContext(SessionContext)
|
||||
const { promiseGet } = useAxios()
|
||||
const { setQcastState } = useContext(QcastContext)
|
||||
const { setQcastState, setIsGlobalLoading } = useContext(QcastContext)
|
||||
|
||||
useEffect(() => {
|
||||
setIsGlobalLoading(true)
|
||||
}, [])
|
||||
|
||||
/**
|
||||
* main search area
|
||||
@ -46,6 +50,7 @@ export const useMainContentsController = () => {
|
||||
businessCharger: res.data.businessCharger,
|
||||
businessChargerMail: res.data.businessChargerMail,
|
||||
})
|
||||
setIsGlobalLoading(false)
|
||||
} else {
|
||||
// setSaleStoreId('')
|
||||
// setSaleStoreName('')
|
||||
|
||||
@ -5663,7 +5663,7 @@ react-datepicker@^7.3.0:
|
||||
prop-types "^15.7.2"
|
||||
react-onclickoutside "^6.13.0"
|
||||
|
||||
"react-dom@^15.5.x || ^16.x || ^17.x || ^18.x", "react-dom@^16.3.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17 || ^18", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", "react-dom@^16.9.0 || ^17 || ^18", react-dom@^18, react-dom@^18.0.0, react-dom@^18.2.0, "react-dom@>= 16.3.0", react-dom@>=16.6.0, react-dom@>=16.8.0, react-dom@>=18:
|
||||
"react-dom@^15.5.x || ^16.x || ^17.x || ^18.x", "react-dom@^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.3.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17 || ^18", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", "react-dom@^16.9.0 || ^17 || ^18", react-dom@^18, react-dom@^18.0.0, react-dom@^18.2.0, "react-dom@>= 16.3.0", react-dom@>=16.6.0, react-dom@>=16.8.0, react-dom@>=18:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz"
|
||||
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
|
||||
@ -5747,6 +5747,11 @@ react-select@^5.8.1:
|
||||
react-transition-group "^4.3.0"
|
||||
use-isomorphic-layout-effect "^1.1.2"
|
||||
|
||||
react-spinners@^0.14.1:
|
||||
version "0.14.1"
|
||||
resolved "https://registry.npmjs.org/react-spinners/-/react-spinners-0.14.1.tgz"
|
||||
integrity sha512-2Izq+qgQ08HTofCVEdcAQCXFEYfqTDdfeDQJeo/HHQiQJD4imOicNLhkfN2eh1NYEWVOX4D9ok2lhuDB0z3Aag==
|
||||
|
||||
react-style-singleton@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz"
|
||||
@ -5775,7 +5780,7 @@ react-transition-group@^4.3.0:
|
||||
loose-envify "^1.4.0"
|
||||
prop-types "^15.6.2"
|
||||
|
||||
react@*, "react@^15.5.x || ^16.x || ^17.x || ^18.x", "react@^16.3.0 || ^17.0.0 || ^18.0.0", "react@^16.8 || ^17 || ^18", "react@^16.8.0 || ^17 || ^18", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", "react@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", "react@^16.9.0 || ^17 || ^18", react@^18, react@^18.0.0, react@^18.2.0, react@^18.3.1, "react@>= 16.3.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", react@>=16.13.1, react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=18:
|
||||
react@*, "react@^15.5.x || ^16.x || ^17.x || ^18.x", "react@^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.3.0 || ^17.0.0 || ^18.0.0", "react@^16.8 || ^17 || ^18", "react@^16.8.0 || ^17 || ^18", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", "react@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", "react@^16.9.0 || ^17 || ^18", react@^18, react@^18.0.0, react@^18.2.0, react@^18.3.1, "react@>= 16.3.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", react@>=16.13.1, react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=18:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz"
|
||||
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user