현재 관리자페이지의 로그인 방식
//SignInPage.tsx
const { firebaseLogin } = useLogin();//useLogin은 react query를 이용한 react hook이다.
const setUser = useSetRecoilState(userState);
await firebaseLogin(
{ email, password },
{
onSuccess: (data) => {
//로그인에 성공했다면 유저의 관리자 여부를 확인해서 recoil에 저장한다.
const user = data as IAuth;
if (user.isAdmin) setUser(user);
},
onError: () => {
setSignInFail(true);
},
}
);
//firebase/auth/index.ts
const login = async (email: string, password: string) => {
//fireAuth에서 id 받아오기
const response = await signInWithEmailAndPassword(FirebaseConfig.auth, email, password);
const { uid } = response.user;
//fireStore에서 관리자 찾아오기
const user = await firebase.firestore.getAdminByUid(uid);
return user;
};
//firebase/firestore/index.ts
const getAdminByUid = async (uid: string) => {
const docRef = doc(FirebaseConfig.db, 'admin', uid);
const docSnap = await getDoc(docRef);
return docSnap.data();
};
//app/index.tsx
function App() {
const user = useRecoilValue(userState);
//유저의 관리자 정보를 이용한 라우팅
return user?.isAdmin ? (
<Routes>
<Route path="/" element={<ServiceIntroAndLocationPage />} />
<Route path="/discount" element={<DiscountAndGuidePage />} />
<Route path="/sitter">
<Route index element={<SuspenseSitterListPage />} />
<Route path=":uid" element={<SuspenseSitterDetailPage />} />
</Route>
<Route path="/user/*" element={<SuspenseUserListPage />} />
<Route path="/careRequest" element={<SuspenseCareRequestListPage />} />
<Route path="*" element={<ServiceIntroAndLocationPage />} />
</Routes>
) : (
<Routes>
<Route path="*" element={<SignInPage />} />
<Route path="/signin" element={<SignInPage />} />
</Routes>
);
}
react는 react-router-dom을 사용해 routing한다.
이를 위해선 App을 BrowserRouter로 감싸주고 App안에 router를 설정해주면 된다.
//src/index.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { RecoilRoot } from 'recoil';
import App from './app';
import reportWebVitals from './reportWebVitals';
import './App.css';
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
const queryClient = new QueryClient();
root.render(
<React.StrictMode>
<BrowserRouter> //라우터
<RecoilRoot> //리코일 상태관리
<QueryClientProvider client={queryClient}> //react query
<App />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</RecoilRoot>
</BrowserRouter>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
App에서 라우터를 설정해주었다.
이름은 index.tsx로 했지만 그냥 App.tsx로 해도 무방
//app/index.tsx
function SuspenseCareRequestListPage() {
return (
//Suspense로 감싸서 react query가 작동 중일 때 자동으로 화면을 관리해준다.
<Suspense fallback={<AdminLayout text="로딩중">로딩중...</AdminLayout>}>
<CareRequestListPage />
</Suspense>
);
}
function App() {
const user = useRecoilValue(userState);
return user?.isAdmin ? (
<Routes>
<Route path="/" element={<ServiceIntroAndLocationPage />} />
<Route path="/discount" element={<DiscountAndGuidePage />} />
<Route path="/sitter">
<Route index element={<SuspenseSitterListPage />} />
<Route path=":uid" element={<SuspenseSitterDetailPage />} />
</Route>
<Route path="/user/*" element={<SuspenseUserListPage />} />
<Route path="/careRequest" element={<SuspenseCareRequestListPage />} />
<Route path="*" element={<ServiceIntroAndLocationPage />} />
</Routes>
) : (
<Routes>
<Route path="*" element={<SignInPage />} />
<Route path="/signin" element={<SignInPage />} />
</Routes>
);
}
라우팅을 일으키는 사이드바는 AdminLayout에 설정해놓았다.
interface LayoutProps {
children: ReactNode;
text: string;
}
interface ListProps {
text: string;
icon: ReactNode;
to: string;
}
function AdminListItem(props: ListProps) {
const { text, icon, to } = props;
return (
<ListItem key="serviceIntroAndRegion" disablePadding>
//Link로 감싸서 routing
<Link to={to} className="text-white w-full">
<ListItemButton sx={{ paddingY: '15px' }}>
<ListItemIcon sx={{ minWidth: '30px', color: 'white', gap: '1rem' }}>
{icon}
{text}
</ListItemIcon>
</ListItemButton>
</Link>
</ListItem>
);
}
function AdminLayout(props: LayoutProps) {
const { children, text } = props;
return (
<Box sx={{ display: 'flex', minHeight: '100vh' }} className=" bg-slate-100">
//사이드바 처럼 생긴 div 화면이 너무 작아지면 글자가 튀어나감
<div className="w-80 bg-slate-700 min-w">
<Toolbar className="bg-slate-900" />
<Divider className="bg-white" />
<List className="flex flex-col">
<AdminListItem text="서비스 소개, 지역 관리" to="/" icon={<LocationOnOutlined className="text-white" />} />
<AdminListItem text="돌보미 관리" to="/sitter" icon={<EscalatorWarningOutlined className="text-white" />} />
<AdminListItem text="할인, 가이드 관리" to="/discount" icon={<ArticleOutlined className="text-white" />} />
<AdminListItem text="전체 유저 관리" to="/user" icon={<SupervisorAccountOutlined className="text-white" />} />
<AdminListItem text="돌봄 요청 관리" to="/careRequest" icon={<SendOutlined className="text-white" />} />
</List>
</div>
</Box>
);
}
export default AdminLayout;
이렇게 되면 라우팅은 끝!