Skip to content

Commit

Permalink
[FEAT] 유저 ROLE 관련 작업 (#122)
Browse files Browse the repository at this point in the history
* feat: 유저 등록 전 마이페이지 접근 제한 기능 구현

* feat: useRegistAlarm path check 개선

* feat: 유저 수정 페이지에서 portfolioInput required 설정정
  • Loading branch information
csk6314 authored Jan 16, 2025
1 parent 2bb9d72 commit f52e066
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 22 deletions.
3 changes: 2 additions & 1 deletion src/features/auth/lib/form.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ export const profileFormValidation = formValidation.shape({
.matches(
/^\s*$|^((ftp|http|https):\/\/)?(www.)?(?!.*(ftp|http|https|www.))[a-zA-Z0-9_-]+(\.[a-zA-Z]+)+((\/)[\w#]+)*(\/\w+\?[a-zA-Z0-9_]+=\w+(&[a-zA-Z0-9_]+=\w+)*)?$/gm,
'URL 형식에 맞게 입력해주세요.',
),
)
.required('포트폴리오 URL을 입력해주세요.'),
});

export const profileFormConfig: FormConfigType<PortfolioFormValues> = {
Expand Down
12 changes: 0 additions & 12 deletions src/pages/MyPage/MyPage.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
import { useNavigate } from 'react-router-dom';

import styles from './MyPage.module.scss';

import { useRoleGuard } from '@/shared/hook/useRoleGuard';
import { ContentLayout, SideTab, useMyTab } from '@/widgets';

export const MyPage = () => {
const navigate = useNavigate();
// REAL_NEWBIE면 register page로 redirect
useRoleGuard({
requiredRoles: ['JUST_NEWBIE', 'ADMIN', 'OLD_NEWBIE', 'USER'],
onAccessDenied: () => {
navigate('/register');
},
});

const { activeTabItem, isActivePath } = useMyTab();
return (
<div className={styles.myPageContainer}>
Expand Down
12 changes: 11 additions & 1 deletion src/shared/hook/useRegistAlarm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,24 @@ import { useUserStore } from '@/features/user/model/user.store';

const excludePath = ['/register', '/my'];

const checkPath = (path: string, pathList: string[]) => {
for (const excludePath of pathList) {
if (path.startsWith(excludePath)) {
return false;
}
}

return true;
};

export const useRegistAlarm = () => {
const navigate = useNavigate();
const location = useLocation();
const userData = useUserStore(state => state.userData);

useEffect(() => {
if (!userData) return;
if (userData.role === 'REAL_NEWBIE' && !excludePath.includes(location.pathname)) {
if (userData.role === 'REAL_NEWBIE' && checkPath(location.pathname, excludePath)) {
void customConfirm({
title: '유저 등록',
text: '아직 등록된 유저 프로필이 없습니다!\n프로필을 등록해주세요.',
Expand Down
5 changes: 3 additions & 2 deletions src/shared/hook/useRoleGuard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import { useShallow } from 'zustand/shallow';

import { customConfirm } from '../ui';

import type { UserDataState } from '@/features/user/model/user.store';
import { useUserStore } from '@/features/user/model/user.store';
import type { UserRole } from '@/features/user/user.dto';

interface UseRoleGuardProps {
requiredRoles: UserRole[]; // 허용된 역할 목록
onAccessDenied?: () => void; // 접근 제한 시 실행할 이벤트
onAccessDenied?: (userData: UserDataState | null) => void; // 접근 제한 시 실행할 이벤트
}

export const useRoleGuard = ({ requiredRoles, onAccessDenied }: UseRoleGuardProps) => {
Expand Down Expand Up @@ -37,7 +38,7 @@ export const useRoleGuard = ({ requiredRoles, onAccessDenied }: UseRoleGuardProp

if (!userData || !requiredRoles.includes(userData.role)) {
if (onAccessDenied) {
onAccessDenied();
onAccessDenied(userData);
} else {
void defaultDeniedHandler();
}
Expand Down
25 changes: 21 additions & 4 deletions src/widgets/SettingUser/ContentLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,33 @@ interface ContentLayoutProps {
export const ContentLayout = ({ activeTab }: ContentLayoutProps) => {
// 로그인한 유저만 접근 가능
const { userData } = useRoleGuard({
requiredRoles: ['ADMIN', 'JUST_NEWBIE', 'OLD_NEWBIE', 'REAL_NEWBIE', 'USER'],
onAccessDenied: () => {
requiredRoles: ['ADMIN', 'JUST_NEWBIE', 'OLD_NEWBIE', 'USER'],
onAccessDenied: userData => {
if (!userData) {
void customConfirm({
title: '잘못된 접근',
text: '유저 정보를 확인할 수 없습니다.\n로그인하고 다시 시도해주세요.',
icon: 'warning',
showCancelButton: false,
allowOutsideClick: false,
}).then(result => {
if (result.isConfirmed) {
navigate('/');
return;
}
});
return;
}

void customConfirm({
title: '잘못된 접근',
text: '유저 정보를 확인할 수 없습니다.\n로그인하고 다시 시도해주세요.',
text: '유저 정보를 확인할 수 없습니다.\n회원 정보를 먼저 등록해주세요.',
icon: 'warning',
showCancelButton: false,
allowOutsideClick: false,
}).then(result => {
if (result.isConfirmed) {
navigate('/');
navigate('/register');
return;
}
});
Expand Down
4 changes: 2 additions & 2 deletions src/widgets/SettingUser/SetProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ export const SetProfile = ({ userData }: SetProfileProps) => {
const { socials, majorJobGroup, minorJobGroup, ...rest } = data;

const majorOption = {
value: majorJobGroup,
value: majorJobGroup || '',
label:
JOB_CATEGORIES.find(majorCatergory => majorCatergory.value === majorJobGroup)?.label ??
'알 수 없음',
};

const minorOption = {
value: minorJobGroup,
value: minorJobGroup || '',
label:
JOB_SUB_CATEGORY.find(minorCategory => minorCategory.value === minorJobGroup)?.label ??
'알 수 없음',
Expand Down

1 comment on commit f52e066

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚡ Lighthouse report for http://localhost:3000/

Category Score
🔴 Performance 27
🟠 Accessibility 86
🟢 Best Practices 92
🟠 SEO 85

Detailed Metrics

Metric Value
🔴 First Contentful Paint 50.8 s
🔴 Largest Contentful Paint 94.2 s
🔴 Total Blocking Time 740 ms
🟢 Cumulative Layout Shift 0.051
🔴 Speed Index 67.4 s

Please sign in to comment.