사용자 삭제 기능 추가
- 헤더 오른쪽 버튼 시스템 구현 - ContextType에 setOnRightClick 추가 - useSetOnRightClick 훅 추가 - HeaderNavigationProps에 onRightClick 추가 - HeaderType.LeftArrow에 오른쪽 삭제 버튼 렌더링 - 사용자 삭제 API 및 타입 추가 - UserDeleteParams, UserDeleteResponse 인터페이스 추가 - use-user-delete-mutation 훅 생성 - API_URL_USER.deleteUser() 엔드포인트 사용 - 사용자 설정 페이지에서 삭제 기능 구현 - 현재 로그인한 사용자가 아닐 경우에만 삭제 버튼 표시 - showConfirm 다이얼로그로 삭제 확인 - 삭제 성공 시 토스트 메시지 표시 및 목록 페이지로 이동 - 목록 페이지에서 refresh 상태로 자동 갱신 - showConfirm 위젯 추가 - Promise 기반의 확인 다이얼로그 - 취소/확인 버튼 지원 - 다국어 지원 (common.cancel, common.confirm) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -12,10 +12,11 @@ import { AppAlarmUnreadCountParams, AppAlarmUnreadCountResponse, MERCHANT_ADMIN_
|
||||
import { useAppAlarmUnreadCountMutation } from '@/entities/alarm/api/use-app-alarm-unread-count-mutation';
|
||||
import { appBridge } from '@/utils/appBridge';
|
||||
|
||||
export const HeaderNavigation = ({
|
||||
onBack,
|
||||
headerTitle,
|
||||
headerType,
|
||||
export const HeaderNavigation = ({
|
||||
onBack,
|
||||
onRightClick,
|
||||
headerTitle,
|
||||
headerType,
|
||||
loginSuccess,
|
||||
mid,
|
||||
setMid
|
||||
@@ -156,11 +157,11 @@ export const HeaderNavigation = ({
|
||||
</div>
|
||||
}
|
||||
{
|
||||
(headerType === HeaderType.LeftArrow) &&
|
||||
(headerType === HeaderType.LeftArrow) &&
|
||||
<div className="header-content">
|
||||
<div className="header-left">
|
||||
<button className="header-btn">
|
||||
<img
|
||||
<img
|
||||
src={ IMAGE_ROOT + '/ico_back.svg' }
|
||||
alt="뒤로가기"
|
||||
onClick={ () => handleBack() }
|
||||
@@ -168,6 +169,17 @@ export const HeaderNavigation = ({
|
||||
</button>
|
||||
</div>
|
||||
<div className="header-center">{ headerTitle }</div>
|
||||
{ onRightClick &&
|
||||
<div className="header-right">
|
||||
<button className="header-btn">
|
||||
<img
|
||||
src={ IMAGE_ROOT + '/ico_delete.svg' }
|
||||
alt="삭제"
|
||||
onClick={ () => onRightClick() }
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
{
|
||||
|
||||
38
src/widgets/show-confirm/index.tsx
Normal file
38
src/widgets/show-confirm/index.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Dialog } from '@/shared/ui/dialogs/dialog';
|
||||
import { overlay } from 'overlay-kit';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const showConfirm = (msg: string): Promise<boolean> => {
|
||||
return new Promise((resolve) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onConfirmClick = () => {
|
||||
resolve(true);
|
||||
};
|
||||
|
||||
const onCancelClick = () => {
|
||||
resolve(false);
|
||||
};
|
||||
|
||||
overlay.open(({
|
||||
isOpen,
|
||||
close,
|
||||
unmount
|
||||
}) => {
|
||||
return (
|
||||
<Dialog
|
||||
afterLeave={ unmount }
|
||||
open={ isOpen }
|
||||
onClose={ () => {
|
||||
resolve(false);
|
||||
close();
|
||||
}}
|
||||
message={ msg }
|
||||
buttonLabel={ [t('common.cancel'), t('common.confirm')] }
|
||||
onConfirmClick={ onConfirmClick }
|
||||
onCancelClick={ onCancelClick }
|
||||
/>
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -39,6 +39,7 @@ import { AlarmRoutes } from '@/entities/alarm/ui/alarm-routes';
|
||||
|
||||
export interface ContextType {
|
||||
setOnBack: (onBack: () => void) => void;
|
||||
setOnRightClick: (onRightClick: () => void) => void;
|
||||
setHeaderTitle: (title: string) => void;
|
||||
setIsPullToRefreshEnabled: (enabled: boolean) => void;
|
||||
setMenuOn: (menuOn: boolean) => void;
|
||||
@@ -65,6 +66,7 @@ export const SubLayout = () => {
|
||||
} = useUserInfo();
|
||||
|
||||
const [onBack, setOnBack] = useState(undefined);
|
||||
const [onRightClick, setOnRightClick] = useState(undefined);
|
||||
const [headerTitle, setHeaderTitle] = useState<string>('');
|
||||
const [headerType, setHeaderType] = useState<HeaderType>(HeaderType.NoHeader);
|
||||
const [footerMode, setFooterMode] = useState<boolean>(false);
|
||||
@@ -405,9 +407,10 @@ export const SubLayout = () => {
|
||||
return (
|
||||
<div className={ wrapperClassName }>
|
||||
<Fragment>
|
||||
<HeaderNavigation
|
||||
onBack={ onBack }
|
||||
headerTitle={ headerTitle }
|
||||
<HeaderNavigation
|
||||
onBack={ onBack }
|
||||
onRightClick={ onRightClick }
|
||||
headerTitle={ headerTitle }
|
||||
headerType={ headerType }
|
||||
key={ headerNavigationKey }
|
||||
loginSuccess={ loginSuccess }
|
||||
@@ -418,6 +421,7 @@ export const SubLayout = () => {
|
||||
<Outlet
|
||||
context={{
|
||||
setOnBack,
|
||||
setOnRightClick,
|
||||
setHeaderTitle,
|
||||
setHeaderType,
|
||||
setFooterMode,
|
||||
|
||||
@@ -19,6 +19,17 @@ export const useSetOnBack = (fn: any) => {
|
||||
return { setOnBack };
|
||||
};
|
||||
|
||||
export const useSetOnRightClick = (fn: any) => {
|
||||
const { setOnRightClick } = useSubLayoutContext();
|
||||
useEffect(() => {
|
||||
setOnRightClick(() => fn);
|
||||
return () => {
|
||||
setOnRightClick(() => undefined);
|
||||
};
|
||||
}, [setOnRightClick]);
|
||||
return { setOnRightClick };
|
||||
};
|
||||
|
||||
export const useSetHeaderTitle = (title: string) => {
|
||||
const { setHeaderTitle } = useSubLayoutContext();
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user