즐겨찾기 추가/삭제 로직 개선 및 스크롤 위치 수정

- 즐겨찾기 삭제 시 최소 1개 유지 검증 추가 (favorite-wrapper.tsx)
- 즐겨찾기 추가/삭제 로직 분리 및 개선 (menu-category.tsx)
  - 추가 시: 최대 10개만 체크
  - 삭제 시: 최소 1개 유지 체크
  - 각 조건에서 early return으로 명확한 흐름 구성
- 메뉴 오픈 시 즐겨찾기 목록 스크롤을 맨 앞으로 초기화
  - prevMenuOn 상태로 메뉴 오픈 감지
  - 추가/삭제 시에만 마지막 아이템으로 스크롤
- 로컬라이제이션 키 추가
  - cannotDeleteLastItem: 최소 1개 유지 메시지
  - cannotAddMoreThan10: 최대 10개 제한 메시지
- snackBar import 추가 및 showAlert에서 snackBar로 변경

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jay Sheen
2025-11-13 17:24:29 +09:00
parent b20c625426
commit 8fbc7d2f74
4 changed files with 71 additions and 38 deletions

View File

@@ -8,6 +8,7 @@ import { useFavoriteEditOnStore, useMenuIds, useMenuOnStore, useStore } from '@/
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { showAlert } from '@/widgets/show-alert'; import { showAlert } from '@/widgets/show-alert';
import { checkGrant } from '@/shared/lib/check-grant'; import { checkGrant } from '@/shared/lib/check-grant';
import { snackBar } from '@/shared/lib';
export interface FavoriteWrapperProps { export interface FavoriteWrapperProps {
usingType: 'home' | 'menu', usingType: 'home' | 'menu',
@@ -27,6 +28,7 @@ export const FavoriteWrapper = ({
const { menuIds, setMenuIds, deleteMenuId} = useMenuIds(); const { menuIds, setMenuIds, deleteMenuId} = useMenuIds();
const [isFirst, setIsFirst] = useState<boolean>(true); const [isFirst, setIsFirst] = useState<boolean>(true);
const [favoriteItems, setFavoriteItems] = useState<Array<UserFavorite>>([]); const [favoriteItems, setFavoriteItems] = useState<Array<UserFavorite>>([]);
const [prevMenuOn, setPrevMenuOn] = useState<boolean>(false);
const itemAdd: UserFavorite = { const itemAdd: UserFavorite = {
menuId: -1, menuId: -1,
@@ -73,6 +75,12 @@ export const FavoriteWrapper = ({
}; };
const onClickToRemoveItem = (item?: UserFavorite) => { const onClickToRemoveItem = (item?: UserFavorite) => {
// 삭제 전에 먼저 개수 체크
if(menuIds.length === 1){
snackBar(t('favorite.cannotDeleteLastItem'));
return; // 삭제 중단
}
let idx = -1; let idx = -1;
let newFavorite: Array<UserFavorite> = favoriteItems.filter((value, index) => { let newFavorite: Array<UserFavorite> = favoriteItems.filter((value, index) => {
if(value.menuId === item?.menuId){ if(value.menuId === item?.menuId){
@@ -80,18 +88,16 @@ export const FavoriteWrapper = ({
} }
return value.menuId !== item?.menuId; return value.menuId !== item?.menuId;
}); });
useStore.getState().UserStore.setUserFavorite(newFavorite); useStore.getState().UserStore.setUserFavorite(newFavorite);
setFavoriteItems(newFavorite); setFavoriteItems(newFavorite);
if(idx > -1){ if(idx > -1){
goToSlide(idx); goToSlide(idx);
} }
if(menuIds.length <= 1){
showAlert('바로가기는 1개이상 설정 필요 합니다.') ; if(item?.menuId){
} deleteMenuId(item?.menuId);
else{
if(item?.menuId){
deleteMenuId(item?.menuId);
}
} }
}; };
@@ -162,16 +168,31 @@ export const FavoriteWrapper = ({
useEffect(() => { useEffect(() => {
getFavoriteList(); getFavoriteList();
if(usingType === 'home'){ if(usingType === 'home'){
goToSlide('first'); goToSlide('first');
} }
else if(usingType === 'menu' && !isFirst){ else if(usingType === 'menu'){
setTimeout(() => { // 메뉴가 새로 열렸는지 확인 (prevMenuOn: false -> menuOn: true)
goToSlide('last'); const isMenuJustOpened = !prevMenuOn && menuOn;
}, 100);
if(isMenuJustOpened || isFirst){
// 메뉴가 새로 열렸거나 처음 렌더링 시 맨 앞으로
setTimeout(() => {
goToSlide('first');
}, 100);
}
else if(changeMenuId){
// 즐겨찾기 아이템 추가/삭제 시 마지막으로 (변경된 항목 보여주기)
setTimeout(() => {
goToSlide('last');
}, 100);
}
} }
setIsFirst(false); setIsFirst(false);
}, [changeMenuId, favoriteEditOn]); setPrevMenuOn(menuOn);
}, [changeMenuId, favoriteEditOn, menuOn]);
return ( return (
<> <>

View File

@@ -7,6 +7,7 @@ import { useTranslation } from 'react-i18next';
import { MenuItems } from '@/entities/common/model/constant'; import { MenuItems } from '@/entities/common/model/constant';
import { showAlert } from '@/widgets/show-alert'; import { showAlert } from '@/widgets/show-alert';
import { checkGrant } from '@/shared/lib/check-grant'; import { checkGrant } from '@/shared/lib/check-grant';
import { snackBar } from '@/shared/lib';
export interface MenuCategoryProps { export interface MenuCategoryProps {
menuId?: number; menuId?: number;
@@ -60,34 +61,41 @@ export const MenuCategory = ({
programPath?: string, programPath?: string,
) => { ) => {
let userFavorite = useStore.getState().UserStore.userFavorite; let userFavorite = useStore.getState().UserStore.userFavorite;
if(userFavorite.length >= 10){
showAlert('즐겨찾기는 10개까지만 추가 할수 있습니다.'); // 추가 시: 최대 10개 체크
if(checked && userFavorite.length >= 10){
snackBar(t('favorite.cannotAddMoreThan10'));
return;
} }
else if(userFavorite.length <= 1){
showAlert('바로가기는 1개이상 설정 필요 합니다.'); // 삭제 시: 최소 1개 체크
if(!checked && userFavorite.length <= 1){
snackBar(t('favorite.cannotDeleteLastItem'));
return;
}
// 추가 또는 삭제 실행
if(checked){
userFavorite = [
...userFavorite,
{
menuId: menuId,
menuName: menuName,
menuNameEng: menuNameEng,
iconFilePath: iconFilePath,
programPath: programPath
}
];
} }
else{ else{
if(checked){ userFavorite = userFavorite.filter((value, _) => {
userFavorite = [ return value.menuId !== menuId
...userFavorite, });
{
menuId: menuId,
menuName: menuName,
menuNameEng: menuNameEng,
iconFilePath: iconFilePath,
programPath: programPath
}
];
}
else{
userFavorite = userFavorite.filter((value, _) => {
return value.menuId !== menuId
});
}
useStore.getState().UserStore.setUserFavorite(userFavorite);
setChangeMenuId(`${menuId}-${checked}`);
callFavoiteItems();
} }
useStore.getState().UserStore.setUserFavorite(userFavorite);
setChangeMenuId(`${menuId}-${checked}`);
callFavoiteItems();
}; };
const callFavoiteItems = () => { const callFavoiteItems = () => {

View File

@@ -357,7 +357,9 @@
"menuPermissions": "Menu Permissions" "menuPermissions": "Menu Permissions"
}, },
"favorite": { "favorite": {
"edit": "Edit" "edit": "Edit",
"cannotDeleteLastItem": "At least one shortcut must be set.",
"cannotAddMoreThan10": "You can set up to 10 shortcuts."
}, },
"footer": { "footer": {
"home": "Home", "home": "Home",

View File

@@ -357,7 +357,9 @@
"menuPermissions": "메뉴별 권한 설정" "menuPermissions": "메뉴별 권한 설정"
}, },
"favorite": { "favorite": {
"edit": "편집하기" "edit": "편집하기",
"cannotDeleteLastItem": "바로가기는 1개 이상 설정 필요합니다.",
"cannotAddMoreThan10": "바로가기는 최대 10개 설정 가능합니다."
}, },
"footer": { "footer": {
"home": "홈", "home": "홈",