관리자 페이지 프로젝트 1 - 로그인 및 라우팅

철판김치덮밥·2022년 12월 20일
2

로그인

현재 관리자페이지의 로그인 방식

  1. fireAuth에 Email과 Password로 로그인 해 uid를 받아온다
  2. firestore admin 컬렉션에 해당 아이디의 doc을 참조해 user를 가져온다.
  3. user가 관리자인 것을 확인했다면 recoil에 담아 자동으로 라우팅에 사용한다.

//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;

이렇게 되면 라우팅은 끝!

0개의 댓글