diff --git a/src/common.module.scss b/src/common.module.scss
index d9e3ab52..5e3edb78 100644
--- a/src/common.module.scss
+++ b/src/common.module.scss
@@ -26,12 +26,14 @@ body {
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
margin: 0;
padding: 0;
- background-color: #F5F5DD;
+ background-color: #FFFFFF;
min-height: 1080px; /* 최소 높이 설정 */
+
}
-main {
+body main {
min-height: 1080px; /* 최소 높이 설정 */
+ padding-top: 60px; /* 헤더 높이만큼 패딩을 추가 */
}
a {
diff --git a/src/components/admin/approval/ApprovalTable.js b/src/components/admin/approval/ApprovalTable.js
index 68e19065..31e4b95f 100644
--- a/src/components/admin/approval/ApprovalTable.js
+++ b/src/components/admin/approval/ApprovalTable.js
@@ -14,6 +14,8 @@ import ApprovalButtons from "./ApprovalButton";
import TansPagination from "./TansPagination";
import TansTable from "./TansTable";
import ApprovalSummary from "./ApprovalSummary";
+import {checkAuthToken, getRefreshToken, getToken, getUserRole} from "../../../utils/authUtil";
+import {useNavigate} from "react-router-dom";
const ApprovalTable = () => {
const [data, setData] = useState([]);
@@ -23,6 +25,7 @@ const ApprovalTable = () => {
const [startDate, setStartDate] = useState(new Date('2024-07-01'));
const [endDate, setEndDate] = useState(new Date());
const [stats, setStats] = useState({});
+ const navigate = useNavigate();
const table = useReactTable({
data,
@@ -37,6 +40,7 @@ const ApprovalTable = () => {
rowSelection,
},
});
+
const fetchApprovals = async () => {
console.log('fetchApprovals 실행중!')
@@ -46,6 +50,9 @@ const ApprovalTable = () => {
// const token = localStorage.getItem('token');
// const refreshToken = localStorage.getItem('refreshToken');
+ let userRole = getUserRole();
+ console.log("userRole :",userRole);
+
const res = await fetch(
`/admin/approve?start=${startISO}&end=${endISO}`,
{
@@ -53,8 +60,8 @@ const ApprovalTable = () => {
headers: {
'Content-Type' : 'application/json',
'Cache-Control': 'no-cache',
- // 'Authorization' : 'Bearer ' + getUserToken(),
- // 'refreshToken': refreshToken,
+ // 'Authorization' : 'Bearer ' + getToken(),
+ // 'refreshToken': getRefreshToken(),
},
});
if(!res.ok) {
@@ -86,6 +93,24 @@ const ApprovalTable = () => {
fetchApprovals();
}, [startDate, endDate]);
+ // useEffect 훅 사용하여 admin이 아닐 경우 접근 제한
+ useEffect(() => {
+ debugger
+ const userInfo = checkAuthToken(navigate);
+
+ if (userInfo) {
+ const requiredRole = 'admin'; // 단일 역할을 설정
+ const userRole = getUserRole(); // 사용자 역할 가져오기
+
+ if (userRole !== requiredRole) { // 문자열 비교
+ alert('접근 권한이 없습니다.');
+ navigate('/main');
+ return;
+ }
+ }
+ },
+ []);
+
return (
diff --git a/src/components/auth/LoginForm.js b/src/components/auth/LoginForm.js
index 155ed0f2..6c8551ae 100644
--- a/src/components/auth/LoginForm.js
+++ b/src/components/auth/LoginForm.js
@@ -28,6 +28,27 @@ const LoginForm = ({ userType, onVerificationSent }) => {
return emailRegex.test(email);
};
+ //admin : customer 테이블에 저장되지만, role은 admin으로 저장됨
+ const checkAdminDupId = async (email) => {
+ try {
+ const response = await fetch(`/customer/check?email=${email}`);
+ const result = await response.json();
+ if (result) {
+ console.log(`입력하신 이메일 [ ${email} ] 은 customer 회원입니다.`);
+ setIsExistingUser(true);
+ return true;
+ } else {
+ console.error(`입력하신 이메일 [ ${email} ] 은 customer 회원이 아닙니다.`);
+ setIsExistingUser(false);
+ return false;
+ }
+ } catch (error) {
+ console.error('Error:', error);
+ return false;
+ }
+ }
+
+ //customer
const checkCustomerDupId = async (email) => {
try {
const response = await fetch(`/customer/check?email=${email}`);
@@ -47,6 +68,7 @@ const LoginForm = ({ userType, onVerificationSent }) => {
}
}
+ //store
const checkStoreDupId = async (email) => {
try {
const response = await fetch(`/store/check?email=${email}`);
@@ -73,6 +95,8 @@ const LoginForm = ({ userType, onVerificationSent }) => {
return await checkCustomerDupId(email);
case 'store':
return await checkStoreDupId(email);
+ case 'admin':
+ return await checkAdminDupId(email);
default:
return false;
}
diff --git a/src/components/auth/SignUpForm.js b/src/components/auth/SignUpForm.js
index 950ba284..7f6b5392 100644
--- a/src/components/auth/SignUpForm.js
+++ b/src/components/auth/SignUpForm.js
@@ -31,6 +31,26 @@ const SignUpForm = ({ userType, onVerificationSent }) => {
return emailRegex.test(email);
};
+ //admin : customer 테이블에 저장되지만, role은 admin으로 저장됨
+ const checkAdminDupId = async (email) => {
+ try {
+ const response = await fetch(`/email/check?email=${email}`);
+ const result = await response.json();
+ if (!result) {
+ console.log(`입력하신 이메일 [ ${email} ] 은 admin 회원이 아닙니다.`);
+ setIsExistingUser(false);
+ return true;
+ } else {
+ console.error(`입력하신 이메일 [ ${email} ] 은 admin 회원입니다.`);
+ setIsExistingUser(true);
+ return false;
+ }
+ } catch (error) {
+ console.error('Error:', error);
+ return false;
+ }
+ };
+
//customer
// 새로운 아이디 -> 중복검사 후 no -> 회원가입하기로 유도
const checkCustomerDupId = async (email) => {
@@ -79,6 +99,8 @@ const checkDupId = async (email) => {
return await checkCustomerDupId(email);
case 'store':
return await checkStoreDupId(email);
+ case 'admin' :
+ return await checkAdminDupId(email);
default:
return false;
}
@@ -99,7 +121,7 @@ const sendVerificationLinkForSignUp = async (email) => {
}),
});
if (response.ok) {
- console.log('이메일이 성공적으로 전달되었습니다.',userType,email);
+ console.log('이메일이 성공적으로 전달되었습니다. usertype, email 확인하기 : ',userType,email);
return true;
} else {
console.error('Failed to send verification link');
diff --git a/src/components/header/MyInfo.js b/src/components/header/MyInfo.js
index 4918898c..093c6896 100644
--- a/src/components/header/MyInfo.js
+++ b/src/components/header/MyInfo.js
@@ -31,6 +31,8 @@ const MyInfo = () => {
localStorage.setItem('userImage', data.productImg);
} else if (getUserRole() === 'customer') {
localStorage.setItem('userImage', data.profileImage);
+ } else if (getUserRole() === 'admin') {
+ localStorage.setItem('userImage', data.profileImage);
}
// 닉네임이 null 일 경우 저장하지 않음
@@ -59,8 +61,12 @@ const MyInfo = () => {
}
return (
+ <>
+ {/*알림창*/}
+
+
-
+
{/*안녕하세요 {getSubName() ? getSubName() : userInfo.email}님!*/}
@@ -86,9 +92,22 @@ const MyInfo = () => {
onClick={() => handleIconClick("/customer")}
/>
>
+ ) : getUserRole() === 'admin' ? (
+ <>
+ {/* Admin 아이콘과 프로필 이미지 */}
+
+

handleIconClick("/customer")}
+ />
+
ADMIN
+ >
) : null}
+ >
);
};
diff --git a/src/components/header/MyInfo.module.scss b/src/components/header/MyInfo.module.scss
index 99f4eb40..c6236c2c 100644
--- a/src/components/header/MyInfo.module.scss
+++ b/src/components/header/MyInfo.module.scss
@@ -7,11 +7,6 @@
margin-left: 60px;
}
-.myInfoContainer {
- display: flex;
- align-items: center;
-}
-
.myIconContainer {
margin-left: auto; /* 오른쪽 끝으로 이동 */
display: flex;
@@ -27,3 +22,20 @@
cursor: pointer;
border: #03684e solid;
}
+
+.admin {
+ position: absolute;
+ top: 55px;
+ font-size: 12px;
+}
+
+@media (max-width: 400px) and (max-height: 844px) {
+ .myIconContainer {
+ display: none;
+ }
+
+ .notificationIcon {
+ position: absolute;
+ left: 40px
+ }
+}
diff --git a/src/components/socket/Notification.module.scss b/src/components/socket/Notification.module.scss
index 2caab420..e51a52aa 100644
--- a/src/components/socket/Notification.module.scss
+++ b/src/components/socket/Notification.module.scss
@@ -68,4 +68,13 @@
50% {
opacity: 0;
}
-}
\ No newline at end of file
+}
+
+// header 알림아이콘 반응형 크기
+@media (max-width: 400px) {
+
+ .notify-icon {
+ position: absolute;
+ right: 10px;
+ }
+}
diff --git a/src/layout/Footer.module.scss b/src/layout/Footer.module.scss
index 1a379fe1..ef929b2f 100644
--- a/src/layout/Footer.module.scss
+++ b/src/layout/Footer.module.scss
@@ -71,10 +71,10 @@
}
.copyRight {
- font-size: 24px;
+ font-size: 22px;
position: absolute;
- bottom: -35px;
right: 100px;
+ bottom: 1px;
}
.footerLinks {
@@ -116,7 +116,13 @@
font-size: 280px;
width: 100%;
max-width: 1920px;
- margin-bottom: -80px;
+ margin-bottom: -40px;
letter-spacing: 15px;
text-align: center;
+}
+
+@media (max-width: 400px) and (max-height: 844px) {
+ .footer {
+ display: none;
+ }
}
\ No newline at end of file
diff --git a/src/layout/Header.js b/src/layout/Header.js
index bba62144..fd72c041 100644
--- a/src/layout/Header.js
+++ b/src/layout/Header.js
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
-import { useNavigate } from 'react-router-dom';
-import {getToken, getRefreshToken, extractArea} from '../utils/authUtil';
+import {Link, useNavigate} from 'react-router-dom';
+import {getToken, getRefreshToken, extractArea, getUserRole} from '../utils/authUtil';
import styles from './Header.module.scss';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import SideBarBtn from "../components/store/mypage-edit/SideBarBtn";
@@ -10,6 +10,9 @@ import MyInfo from "../components/header/MyInfo";
import {getCurrentLocation, initializeNaverMapsForHeader, reverseGeocode} from "../utils/locationUtil";
import SidebarModal from "../components/header/SidebarModal";
import SearchInput from "../components/search/SearchInput";
+import SideBar from "../components/store/mypage-edit/SideBar";
+import Edit from "../components/store/mypage-edit/Edit";
+import Notification from "../components/socket/Notification";
// 아이콘을 라이브러리에 추가
library.add(faMagnifyingGlass);
@@ -73,54 +76,62 @@ const Header = () => {
let userArea = extractArea();
+ // 햄버거 버튼 기존 기능 되도록 수정
+ const showHandler = () => {
+ setShow(prev => !prev);
+ }
+
return (
- {/* 햄버거 버튼 */}
- {width > 400 && }
-
- {/* 로고 */}
-
-
- {/* 현재 위치 */}
-
- {userArea}
- ・
- Now
-
-
-
- {/* 상점 검색 칸 */}
- {/*로그인을 하지 않아도 검색칸은 보이되, 로그인이 필요한 서비스 안내하기*/}
- {
- getToken() &&
-
-
-
+ {/* 햄버거 버튼 */}
+ {width <= 400 &&
}
+
+
+
+
+
+ {/* 로고 */}
+
+
+ {/* 현재 위치 */}
+
+ {userArea}
+ ・
+ Now
+
+
+
+ {/* 상점 검색 칸 */}
+ {/*로그인을 하지 않으면 검색창이 사라짐*/}
+ {
+ getToken() &&
+
+
+
+
+ }
+
+ {/*리뷰 커뮤니티 메인*/}
+
+
+ {/* 로그인 및 회원가입 버튼 */}
+
+ {isAuthenticated ? (
+
+ ) : (
+ <>
+
+
・
+
+ >
+ )}
- }
-
- {/*리뷰 커뮤니티 메인*/}
-
-
-
- {/* 로그인 및 회원가입 버튼 */}
-
- {isAuthenticated ? (
-
- ) : (
- <>
-
-
・
-
- >
- )}
-
- {/* 모달 */}
- {modalVisible && }
-
- );
+ {/* 모달 */}
+ {modalVisible && }
+
+);
}
export default Header;
diff --git a/src/layout/Header.module.scss b/src/layout/Header.module.scss
index eb407e3b..ea2f53a7 100644
--- a/src/layout/Header.module.scss
+++ b/src/layout/Header.module.scss
@@ -19,6 +19,11 @@ button {
max-width: 1920px; /* 최대 너비를 1920px로 제한 */
margin: 0 auto; /* 중앙 정렬 */
background-color: #F5F5DD;
+
+ position: fixed; /* 화면에 고정 */
+ top: 0; /* 화면 상단에 위치 */
+ left: 0; /* 왼쪽에 고정 */
+ z-index: 1000; /* 다른 요소 위에 위치 */
}
/* 로고 버튼 */
@@ -29,6 +34,7 @@ button {
background-size: contain;
background-repeat: no-repeat;
margin-left: 70px;
+ cursor: pointer;
}
/* 현재 위치 버튼 스타일 */
@@ -150,3 +156,102 @@ button {
margin-top: 5px;
margin-left: 10px;
}
+
+// 햄버거 버튼 반응형 기능 안됨으로 인한 css 추가
+.container {
+ width: 80%;
+ margin: 20px auto 0;
+ border: 1px solid #ccc;
+ border-radius: 15px;
+ display: flex;
+ background: white;
+}
+
+@media (max-width: 400px) {
+ .container {
+ width: 100%;
+ border: none;
+ margin-top: 0;
+ }
+}
+
+// 반응형 헤더
+@media (max-width: 400px) {
+ .header {
+ flex-direction: row; /* 요소들을 가로로 정렬 */
+ align-items: center; /* 세로 가운데 정렬 */
+ padding: 10px;
+ height: 60px;
+ }
+
+ .logoBtn {
+ position: absolute;
+ height: 40px;
+ width: 40px;
+ margin-left: 60px;
+ }
+
+ .locationPinIcon {
+ //position: absolute;
+ //height: 32px; /* 크기를 줄이지 않음 */
+ //width: 32px;
+ //margin-left: 10px;
+ display: none;
+ }
+
+ .selectedAreaCategoryBtn {
+ position: absolute;
+ height: 15px;
+ width: 15px;
+ margin-left: 5px;
+ margin-top: 0;
+ left: 200px;
+ }
+
+ // 각종 기능은 드롭다운모달로 볼 수있게 설정?
+ .reviewMainIcon {
+ //position: absolute;
+ //right: 5px;
+ //height: 40px; /* 크기를 줄이지 않음 */
+ //width: 40px;
+ //margin-left: 10px;
+ display: none;
+ }
+
+ //반응형일시 현재위치 렌더링 안함, 드롭다운으로 볼 수 있게 설정해보기.
+ .areaName {
+ display: none;
+ }
+
+ .selectedAreaCategory {
+ font-size: 16px;
+ margin-left: 5px;
+ margin-bottom: 0; /* 아래쪽 여백 제거 */
+ }
+
+ .searchStoreSection {
+ width: 120px;
+ padding: 0 10px;
+ background-color: rgba(6, 101, 78, 0.5); /* 투명도 증가 */
+ margin-left: 0; /* or 조정된 값으로 변경 */
+ }
+
+ .loginBtnSection {
+ display: flex;
+ flex-direction: row; /* 버튼들을 가로로 정렬 */
+ gap: 5px;
+ margin-left: auto; /* 오른쪽으로 밀기 */
+ margin-top: 0;
+ }
+
+ .signInBtn, .signUpBtn {
+ font-size: 16px;
+ margin: 0;
+ }
+
+ .dot {
+ margin-left: 0;
+ margin-top: 0;
+ display: none; /* 점 제거 */
+ }
+}
\ No newline at end of file
diff --git a/src/pages/auth/LoginPage.js b/src/pages/auth/LoginPage.js
index 35ea7dd9..675ae2ea 100644
--- a/src/pages/auth/LoginPage.js
+++ b/src/pages/auth/LoginPage.js
@@ -28,32 +28,40 @@ const LoginPage = () => {
{!verificationSent && ( // 이메일 발송 후 사용자 유형 버튼 숨기기
-
-
+
+
+
)}
-
-
+ onResendEmail={handleResendEmail}
+ onVerificationSent={handleVerificationSent}
+ verificationSent={verificationSent} // verificationSent 상태 전달
+ />
+
sign up 🌱
diff --git a/src/pages/auth/SignUpPage.js b/src/pages/auth/SignUpPage.js
index fa6a4e2c..29fa4757 100644
--- a/src/pages/auth/SignUpPage.js
+++ b/src/pages/auth/SignUpPage.js
@@ -12,10 +12,12 @@ const SignUpPage = () => {
setUserType(type);
};
- const handleSignUp = (email, password) => {
- console.log('User Sign Up:', email, password);
+ const handleSignUp = (email, userType) => {
+ console.log('User Sign Up:', email, userType);
+ // 여기서 userType을 백엔드에 전달하여 처리
};
+
const handleResendEmail = () => {
console.log('이메일 재전송 버튼 누름 !');
};
@@ -48,6 +50,14 @@ const SignUpPage = () => {
>
Store
+
)}
{
const userInfo = await checkAuthToken(navigate);
if (userInfo) {
- const requiredRole = 'customer'; // 필요한 role 작성 필요
- if (userInfo.userType !== requiredRole) {
+ const requiredRoles = ['customer', 'admin']; // 필요한 역할 목록
+ if (!requiredRoles.includes(userInfo.userType)) {
alert('접근 권한이 없습니다.');
navigate('/main');
return;
diff --git a/src/utils/authUtil.js b/src/utils/authUtil.js
index ce98a841..6b002c84 100644
--- a/src/utils/authUtil.js
+++ b/src/utils/authUtil.js
@@ -136,6 +136,10 @@ export const checkAuthToken = async (navigate) => {
const userType = tokenInfo.role;
const email = tokenInfo.sub;
+ console.log(tokenInfo);
+ console.log(userType);
+ console.log(email);
+
return {token, refreshToken, userType, email};
}