diff --git a/src/entities/common/model/constant.ts b/src/entities/common/model/constant.ts index 0318fff..6c5e3f3 100644 --- a/src/entities/common/model/constant.ts +++ b/src/entities/common/model/constant.ts @@ -33,4 +33,66 @@ export const BottomSheetMotionVaiants = { }; export const BottomSheetMotionDuration = { duration: 0.3 -}; \ No newline at end of file +}; + +export const MenuItems = [ + {menuId: '30', parent: '30', menuName: '거래조회', subMenu: + [ + {menuId: '31', parent: '30', menuName: '거래내역조회'}, + {menuId: '32', parent: '30', menuName: '현금영수증 발행'}, + {menuId: '33', parent: '30', menuName: '에스크로'}, + {menuId: '34', parent: '30', menuName: '빌링'} + ] + }, + {menuId: '35', parent: '35', menuName: '정산조회', subMenu: + [ + {menuId: '36', parent: '35', menuName: '정산달력'}, + {menuId: '37', parent: '35', menuName: '정산내역'}, + ] + }, + {menuId: '38', parent: '38', menuName: '가맹점 관리', subMenu: + [ + {menuId: '39', parent: '38', menuName: '가맹점 정보'}, + {menuId: '40', parent: '38', menuName: '등록 현황'}, + ] + }, + {menuId: '41', parent: '41', menuName: '결제 관리', subMenu: + [ + {menuId: '42', parent: '41', menuName: '결제 정보'}, + {menuId: '43', parent: '41', menuName: '결제데이터통보'}, + ] + }, + {menuId: '44', parent: '44', menuName: '계정관리', subMenu: + [ + {menuId: '45', parent: '44', menuName: '사용자관리'}, + {menuId: '46', parent: '44', menuName: '비밀번호관리'}, + ] + }, + {menuId: '47', parent: '47', menuName: '부가세신고자료', subMenu: + [ + {menuId: '48', parent: '47', menuName: '부가세신고자료'}, + {menuId: '49', parent: '47', menuName: '부가세참고'}, + ] + }, + {menuId: '50', parent: '50', menuName: '부가서비스', subMenu: + [ + {menuId: '51', parent: '50', menuName: '부가서비스소개'}, + {menuId: '52', parent: '50', menuName: '신용카드ARS카드결제'}, + {menuId: '53', parent: '50', menuName: '계좌이체ARS카드결제'}, + {menuId: '54', parent: '50', menuName: '가상계좌ARS카드결제'}, + {menuId: '55', parent: '50', menuName: '휴대폰ARS카드결제'}, + {menuId: '56', parent: '50', menuName: '계좌간편결제ARS카드결제'}, + {menuId: '57', parent: '50', menuName: 'SSG머니ARS카드결제'}, + {menuId: '58', parent: '50', menuName: 'SSG은행계좌ARS카드결제'}, + {menuId: '59', parent: '50', menuName: '문화상품권ARS카드결제'}, + {menuId: '60', parent: '50', menuName: '티머니페이ARS카드결제'}, + ] + }, + {menuId: '61', parent: '61', menuName: '고객지원', subMenu: + [ + {menuId: '62', parent: '61', menuName: '공지사항'}, + {menuId: '63', parent: '61', menuName: '자주묻는질문'}, + {menuId: '64', parent: '61', menuName: '1:1문의'}, + ] + }, + ] \ No newline at end of file diff --git a/src/entities/common/model/store.ts b/src/entities/common/model/store.ts index 6086bc0..a4af7c6 100644 --- a/src/entities/common/model/store.ts +++ b/src/entities/common/model/store.ts @@ -7,18 +7,22 @@ export interface BannerInfoState { setBannerInfo: (update: SetStateAction>) => void; }; -const initialState = { +const initialBannerInfoState = { bannerInfo: {} as BannerInfo, } as BannerInfoState; export const createBannerInfoStore = lens((set, get) => ({ - ...initialState, + ...initialBannerInfoState, setBannerInfo: (update) => { set((state: BannerInfoState) => { - const newBannerInfo = typeof update === 'function' ? update(state.bannerInfo) : update; + const newBannerInfo = (typeof update === 'function') + ? update(state.bannerInfo): update; return { ...state, - bannerInfo: { ...state.bannerInfo, ...newBannerInfo }, + bannerInfo: { + ...state.bannerInfo, + ...newBannerInfo + }, }; }); }, diff --git a/src/entities/common/model/types.ts b/src/entities/common/model/types.ts index 43608a4..8b623b3 100644 --- a/src/entities/common/model/types.ts +++ b/src/entities/common/model/types.ts @@ -69,11 +69,13 @@ export interface HeaderNavigationProps { menuOn: boolean; headerType: HeaderType; setMenuOn: (menuOn: boolean) => void; + favoriteEdit?: boolean; }; export interface FooterProps { setMenuOn: (menuOn: boolean) => void; footerCurrentPage?: string | null; + setFavoriteEdit: (favoriteEdit: boolean) => void; }; export enum FooterItemActiveKey { Home = 'Home', diff --git a/src/entities/home/model/types.ts b/src/entities/home/model/types.ts index 5ee44f3..5a754ce 100644 --- a/src/entities/home/model/types.ts +++ b/src/entities/home/model/types.ts @@ -3,10 +3,6 @@ import { NoticeListResponse } from '@/entities/support/model/types'; -export interface FavoriteItemProps { - img?: string, - text?: string -}; export interface HomeBottomBannerProps { setBottomBannerOn: (bottomBannerOn: boolean) => void; bottomBannerOn: boolean; diff --git a/src/entities/home/ui/favorite-item.tsx b/src/entities/home/ui/favorite-item.tsx deleted file mode 100644 index 2c01a2f..0000000 --- a/src/entities/home/ui/favorite-item.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { FavoriteItemProps } from '../model/types'; - -export const FavoriteItem = ({ - img, - text -}: FavoriteItemProps) => { - return ( - <> -
-
- { -
- { text } -
- - ); -}; diff --git a/src/entities/home/ui/favorite-wrapper.tsx b/src/entities/home/ui/favorite-wrapper.tsx index 1ef268d..e6b4026 100644 --- a/src/entities/home/ui/favorite-wrapper.tsx +++ b/src/entities/home/ui/favorite-wrapper.tsx @@ -1,56 +1,98 @@ +import { useEffect, useState } from 'react'; +import { useNavigate } from '@/shared/lib/hooks/use-navigate'; import { Swiper, SwiperSlide } from 'swiper/react'; import 'swiper/css'; import { IMAGE_ROOT } from '@/shared/constants/common'; -import { FavoriteItem } from './favorite-item'; -import { FavoriteItemProps } from '../model/types' +import { UserFavorite } from '@/entities/user/model/types'; +import { useStore } from '@/shared/model/store'; +/* +const items: Array = [ + {img: IMAGE_ROOT + '/ico_menu_01.svg', title: '지급대행'}, + {img: IMAGE_ROOT + '/ico_menu_02.svg', title: '거래내역조회'}, + {img: IMAGE_ROOT + '/ico_menu_03.svg', title: '정산달력'}, + {img: IMAGE_ROOT + '/ico_menu_02.svg', title: '거래내역조회'}, + {img: IMAGE_ROOT + '/ico_menu_03.svg', title: '정산달력'} +]; +*/ +export interface FavoriteWrapperProps { + usingType: 'home' | 'menu' +}; -export const FavoriteWrapper = () => { - const items: Array = [ - {img: IMAGE_ROOT + '/ico_menu_01.svg', text: '지급대행'}, - {img: IMAGE_ROOT + '/ico_menu_02.svg', text: '거래내역조회'}, - {img: IMAGE_ROOT + '/ico_menu_03.svg', text: '정산달력'}, - {img: IMAGE_ROOT + '/ico_menu_02.svg', text: '거래내역조회'}, - {img: IMAGE_ROOT + '/ico_menu_03.svg', text: '정산달력'} - ]; +export const FavoriteWrapper = ({ + usingType +}: FavoriteWrapperProps) => { + const { navigate } = useNavigate(); - const itemAdd = { + const [edit, setEdit] = useState(false); + const [favoriteItems, setFavoriteItems] = useState>([]); + + + const itemAdd: UserFavorite = { img: IMAGE_ROOT + '/ico_menu_plus.svg', - text: '편집하기' + title: '편집하기' + }; + + const onClickToFavoriteEdit = () => { + setEdit(true); }; - const getItems = () => { + //useSetFavoriteEdit(true); + //useSetMenuOn(true); + + const onClickToNavigate = (path?: string) => { + if(!!path){ + navigate(path); + } + }; + + const getFavoriteItems = () => { let rs = []; - for(let i=0;i - + +
onClickToNavigate(favoriteItems[i]?.path) } + > +
+ { +
+ { favoriteItems[i]?.title } +
); } + rs.push( + +
+
+ { +
+ { itemAdd.title } +
+
+ ); + return rs; }; return ( <> - { getItems() } - - - - + spaceBetween={ 9 } + slidesPerView={ 4 } + >{ getFavoriteItems() } ); }; diff --git a/src/entities/menu/model/types.ts b/src/entities/menu/model/types.ts index 5b45a0e..e449281 100644 --- a/src/entities/menu/model/types.ts +++ b/src/entities/menu/model/types.ts @@ -3,8 +3,10 @@ export interface MenuCategoryItem { path: string; }; export interface MenuCategoryProps { + key: string; category: string; categoryIcon?: string; items: Array; setMenuOn: (menuOn: boolean) => void; + favoriteEdit?: boolean; }; diff --git a/src/entities/menu/ui/menu-category.tsx b/src/entities/menu/ui/menu-category.tsx index 9b05066..32c6bf5 100644 --- a/src/entities/menu/ui/menu-category.tsx +++ b/src/entities/menu/ui/menu-category.tsx @@ -1,35 +1,70 @@ -import { PATHS } from '@/shared/constants/paths'; -import { IMAGE_ROOT } from '@/shared/constants/common'; import { useNavigate } from '@/shared/lib/hooks/use-navigate'; import { MenuCategoryProps } from '../model/types'; +import { useStore } from '@/shared/model/store'; +import { IMAGE_ROOT } from '@/shared/constants/common'; export const MenuCategory = ({ category, categoryIcon, items, - setMenuOn + setMenuOn, + favoriteEdit }: MenuCategoryProps) => { const { navigate } = useNavigate(); const onClickToNavigate = (path?: string) => { - if(!!path){ + if(!!path && !favoriteEdit){ setMenuOn(false); navigate(path); } }; + const favoriteSetting = ( + checked: boolean, + title?: string, + path?: string + ) => { + useStore.getState().UserStore.setUserFavorite([{ + title: title, + img: IMAGE_ROOT + '/ico_menu_01.svg', + path: path, + }]); + }; + const getMenuItems = () => { let rs = []; for(let i=0;i onClickToNavigate(path) } - >{ title } - ); + if(!!favoriteEdit){ + rs.push( +
  • onClickToNavigate(items[i]?.path) } + > + { items[i]?.title } +
    + favoriteSetting(e.target.checked, items[i]?.title, items[i]?.path) } + /> + +
    +
  • + ); + } + else{ + rs.push( +
  • onClickToNavigate(items[i]?.path) } + >{ items[i]?.title }
  • + ); + } + } return rs; }; diff --git a/src/entities/user/model/store.ts b/src/entities/user/model/store.ts index 4881562..80266fd 100644 --- a/src/entities/user/model/store.ts +++ b/src/entities/user/model/store.ts @@ -1,26 +1,33 @@ import { lens } from '@dhmk/zustand-lens'; import { SetStateAction } from 'react'; -import { UserInfo } from './types'; +import { UserFavorite, UserInfo } from './types'; import { StorageKeys } from '@/shared/constants/local-storage'; export interface UserInfoState { userInfo: UserInfo; setUserInfo: (update: SetStateAction>) => void; resetUserInfo: () => void; + userFavorite: Array; + setUserFavorite: (update: SetStateAction>) => void; }; -const initialState = { +const initialUserInfoState = { userInfo: {} as UserInfo, + userFavorite: [] as Array } as UserInfoState; export const createUserInfoStore = lens((set, get) => ({ - ...initialState, + ...initialUserInfoState, setUserInfo: (update) => { set((state: UserInfoState) => { - const newUserInfo = typeof update === 'function' ? update(state.userInfo) : update; + const newUserInfo = (typeof update === 'function') + ? update(state.userInfo): update; return { ...state, - userInfo: { ...state.userInfo, ...newUserInfo }, + userInfo: { + ...state.userInfo, + ...newUserInfo + }, }; }); }, @@ -34,6 +41,19 @@ export const createUserInfoStore = lens((set, get) => ({ window.localStorage.removeItem(StorageKeys.Usrid); // window.localStorage.removeItem(StorageKeys.ClientAddressIP); // window.localStorage.removeItem(StorageKeys.Requires2FA); - set(initialState); + set(initialUserInfoState); + }, + setUserFavorite: (update) => { + set((state: UserInfoState) => { + const newUserFavorite = (typeof update === 'function') + ? update(state.userFavorite): update; + return { + ...state, + userFavorite: { + ...state.userFavorite, + ...newUserFavorite + }, + }; + }); }, })); diff --git a/src/entities/user/model/types.ts b/src/entities/user/model/types.ts index c923810..d4e5a0b 100644 --- a/src/entities/user/model/types.ts +++ b/src/entities/user/model/types.ts @@ -28,6 +28,11 @@ export interface LoginResponse { requires2FA?: boolean; }; +export interface UserFavorite { + title?: string; + img?: string; + path?: string; +}; export interface UserInfo extends LoginResponse { status: boolean; error?: ErrorResponse; diff --git a/src/pages/home/home-page.tsx b/src/pages/home/home-page.tsx index 98c985f..df3a90c 100644 --- a/src/pages/home/home-page.tsx +++ b/src/pages/home/home-page.tsx @@ -15,16 +15,25 @@ import { useSetHeaderTitle, useSetHeaderType, useSetFooterMode, - useSetFooterCurrentPage + useSetFooterCurrentPage, + useSetFavoriteEdit, + useSetMenuOn } from '@/widgets/sub-layout/use-sub-layout'; export const HomePage = () => { const { callLogin } = useUserInfo(); - const { isNativeEnvironment, openBiometricRegistrationPopup, requestToken, logout } = useAppBridge(); + const { + isNativeEnvironment, + openBiometricRegistrationPopup, + requestToken, + logout + } = useAppBridge(); useSetHeaderTitle(''); useSetHeaderType(HeaderType.Home); useSetFooterMode(true); useSetFooterCurrentPage(FooterItemActiveKey.Home); + //useSetFavoriteEdit(true); + //useSetMenuOn(true); const today = moment().format('YYYYMMDD').toString(); let bannerToday = getLocalStorage(StorageKeys.BottomBannerClose); @@ -189,7 +198,9 @@ export const HomePage = () => {
    { loginSuccess && <> - + } diff --git a/src/shared/constants/paths.ts b/src/shared/constants/paths.ts index 4aa9a72..02499ed 100644 --- a/src/shared/constants/paths.ts +++ b/src/shared/constants/paths.ts @@ -305,6 +305,13 @@ export const PATHS: RouteNamesType = { ROUTE_NAMES.additionalService.payout.request, ), }, + faceAuth: { + base: generatePath(`${ROUTE_NAMES.additionalService.base}${ROUTE_NAMES.additionalService.faceAuth.base}`), + list: generatePath( + `${ROUTE_NAMES.additionalService.base}${ROUTE_NAMES.additionalService.faceAuth.base}`, + ROUTE_NAMES.additionalService.faceAuth.list, + ), + } }, support: { base: generatePath(ROUTE_NAMES.support.base), diff --git a/src/shared/constants/route-names.ts b/src/shared/constants/route-names.ts index b255db4..b894549 100644 --- a/src/shared/constants/route-names.ts +++ b/src/shared/constants/route-names.ts @@ -131,6 +131,10 @@ export const ROUTE_NAMES = { detail: 'detail', request: 'request', }, + faceAuth: { + base: '/face-auth/*', + list: 'list', + } }, support: { diff --git a/src/shared/ui/menu/index.tsx b/src/shared/ui/menu/index.tsx index 48ea5fc..5672442 100644 --- a/src/shared/ui/menu/index.tsx +++ b/src/shared/ui/menu/index.tsx @@ -10,10 +10,12 @@ import { FilterMotionDuration, FilterMotionStyle, FilterMotionVariants } from '@ export interface MenuProps { menuOn: boolean; setMenuOn: (menuOn: boolean) => void; + favoriteEdit?: boolean; }; export const Menu = ({ menuOn, - setMenuOn + setMenuOn, + favoriteEdit }: MenuProps) => { const { navigate } = useNavigate(); const userInfo = useStore((state) => state.UserStore.userInfo); @@ -24,8 +26,7 @@ export const Menu = ({ }; const onClickToMenuClose = () => { setMenuOn(false); - }; - + }; const menuCategoryItems = { transaction: { @@ -93,6 +94,7 @@ export const Menu = ({ {title: '자금이체', path: PATHS.additionalService.fundAccount.transferList}, {title: '정산대행', path: PATHS.additionalService.settlementAgency.manage}, {title: '지급대행', path: PATHS.additionalService.payout.list}, + {title: '안면인증', path: PATHS.additionalService.faceAuth.list} ] }, support: { @@ -105,12 +107,7 @@ export const Menu = ({ ] }, } - - const variants = { - hidden: { x: '100%' }, - visible: { x: '0%' }, - }; - + const getMenuCategory = () => { let rs = []; for (const [key, value] of Object.entries(menuCategoryItems)) { @@ -121,6 +118,7 @@ export const Menu = ({ categoryIcon={ value.categoryIcon } items={ value.items } setMenuOn={ setMenuOn } + favoriteEdit={ favoriteEdit } /> ); } @@ -139,25 +137,38 @@ export const Menu = ({ >
    -
    { 'nictest001m' } (madzoneviper)
    +
    + { 'nictest001m' } + (madzoneviper) +
    - { } + { + + }
    diff --git a/src/widgets/navigation/footer.tsx b/src/widgets/navigation/footer.tsx index 95da813..4780f99 100644 --- a/src/widgets/navigation/footer.tsx +++ b/src/widgets/navigation/footer.tsx @@ -9,7 +9,8 @@ import { useEffect, useState } from 'react'; export const FooterNavigation = ({ setMenuOn, - footerCurrentPage + footerCurrentPage, + setFavoriteEdit }: FooterProps) => { const { navigate } = useNavigate(); const [isFooterOn, setIsFooterOn] = useState(false); @@ -20,6 +21,7 @@ export const FooterNavigation = ({ } }; const onClickToOpenMenu = () => { + setFavoriteEdit(false); setMenuOn(true); }; diff --git a/src/widgets/navigation/header.tsx b/src/widgets/navigation/header.tsx index 2f9ec0b..0ca9f27 100644 --- a/src/widgets/navigation/header.tsx +++ b/src/widgets/navigation/header.tsx @@ -12,7 +12,8 @@ export const HeaderNavigation = ({ headerTitle, menuOn, headerType, - setMenuOn + setMenuOn, + favoriteEdit }: HeaderNavigationProps) => { const { navigate, @@ -49,6 +50,7 @@ export const HeaderNavigation = ({ } { diff --git a/src/widgets/sub-layout/index.tsx b/src/widgets/sub-layout/index.tsx index fff7c22..c34cfbe 100644 --- a/src/widgets/sub-layout/index.tsx +++ b/src/widgets/sub-layout/index.tsx @@ -9,14 +9,16 @@ import { PullToRefresh } from '@/widgets/pull-to-refresh/pull-to-refresh'; import { useNavigate } from '@/shared/lib/hooks'; import { useScrollToTop } from '@/shared/lib/hooks/use-scroll-to-top'; import { HeaderType } from '@/entities/common/model/types'; + export interface ContextType { setOnBack: (onBack: () => void) => void; setHeaderTitle: (title: string) => void; setIsPullToRefreshEnabled: (enabled: boolean) => void; - setMenuOn:(on: boolean) => void; + setMenuOn: (menuOn: boolean) => void; setHeaderType: (headerType: HeaderType) => void; - setFooterMode:(footMode: boolean) => void; - setFooterCurrentPage:(currentPage?: string | null) => void; + setFooterMode: (footerMode: boolean) => void; + setFooterCurrentPage: (footerCurrentPage?: string | null) => void; + setFavoriteEdit: (favoriteEdit?: boolean) => void; }; export const SubLayout = () => { @@ -29,7 +31,8 @@ export const SubLayout = () => { const [headerType, setHeaderType] = useState(HeaderType.NoHeader); const [footerMode, setFooterMode] = useState(false); const [footerCurrentPage, setFooterCurrentPage] = useState(undefined); - + const [favoriteEdit, setFavoriteEdit] = useState(false); + const wrapperClassName = 'wrapper'; return ( @@ -45,6 +48,7 @@ export const SubLayout = () => { menuOn={ menuOn } setMenuOn={ setMenuOn } headerType={ headerType } + favoriteEdit={ favoriteEdit } /> { setMenuOn, setHeaderType, setFooterMode, - setFooterCurrentPage + setFooterCurrentPage, + setFavoriteEdit }} /> { @@ -62,6 +67,7 @@ export const SubLayout = () => { } diff --git a/src/widgets/sub-layout/use-sub-layout.ts b/src/widgets/sub-layout/use-sub-layout.ts index 18d07b7..9a09dac 100644 --- a/src/widgets/sub-layout/use-sub-layout.ts +++ b/src/widgets/sub-layout/use-sub-layout.ts @@ -1,9 +1,8 @@ -/* eslint-disable react-hooks/exhaustive-deps */ -import { ReactNode, useEffect } from 'react'; +import { useEffect } from 'react'; import { useOutletContext } from 'react-router'; -import { ContextType } from '.'; import { FooterItemActiveKey } from '@/entities/common/model/types'; import { HeaderType } from '@/entities/common/model/types'; +import { ContextType } from '.'; export const useSubLayoutContext = () => { return useOutletContext(); @@ -25,7 +24,7 @@ export const useSetHeaderTitle = (title: string) => { useEffect(() => { setHeaderTitle(title); return () => setHeaderTitle(''); - }, [setHeaderTitle]); + }, [title, setHeaderTitle]); return { setHeaderTitle }; }; @@ -34,16 +33,16 @@ export const useSetIsPullToRefreshEnabled = (enabled: boolean) => { useEffect(() => { setIsPullToRefreshEnabled(enabled); return () => setIsPullToRefreshEnabled(false); - }, [setIsPullToRefreshEnabled, enabled]); + }, [enabled, setIsPullToRefreshEnabled]); return { setIsPullToRefreshEnabled }; }; -export const useSetMenuOn = (on: boolean) => { +export const useSetMenuOn = (menuOn: boolean) => { const { setMenuOn } = useSubLayoutContext(); useEffect(() => { - setMenuOn(on); + setMenuOn(menuOn); return () => setMenuOn(false); - }, [setMenuOn, on]); + }, [menuOn, setMenuOn]); return { setMenuOn }; }; @@ -52,16 +51,25 @@ export const useSetHeaderType = (headerType: HeaderType) => { useEffect(() => { setHeaderType(headerType); return () => setHeaderType(HeaderType.NoHeader); - }, [setHeaderType]); + }, [headerType, setHeaderType]); return { setHeaderType }; }; +export const useSetFavoriteEdit = (favoriteEdit: boolean) => { + const { setFavoriteEdit } = useSubLayoutContext(); + useEffect(() => { + setFavoriteEdit(favoriteEdit); + return () => setFavoriteEdit(false); + }, [favoriteEdit, setFavoriteEdit]); + return { setFavoriteEdit } +}; + export const useSetFooterMode = (footerMode: boolean) => { const { setFooterMode } = useSubLayoutContext(); useEffect(() => { setFooterMode(footerMode); return () => setFooterMode(false); - }, [setFooterMode, footerMode]); + }, [footerMode, setFooterMode]); return { setFooterMode }; }; @@ -70,6 +78,6 @@ export const useSetFooterCurrentPage = (footerCurrentPage?: FooterItemActiveKey useEffect(() => { setFooterCurrentPage(footerCurrentPage); return () => setFooterCurrentPage(undefined); - }, [setFooterCurrentPage, footerCurrentPage]); + }, [footerCurrentPage, setFooterCurrentPage]); return { setFooterCurrentPage }; }; \ No newline at end of file