@sonhoseong/mfa-lib 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +172 -0
  2. package/dist/components/button/ScrollTopButton.d.ts +5 -0
  3. package/dist/components/button/ScrollTopButton.d.ts.map +1 -0
  4. package/dist/components/button/ScrollTopButton.js +28 -0
  5. package/dist/components/button/index.d.ts +3 -0
  6. package/dist/components/button/index.d.ts.map +1 -0
  7. package/dist/components/button/index.js +2 -0
  8. package/dist/components/button/types/index.d.ts +10 -0
  9. package/dist/components/button/types/index.d.ts.map +1 -0
  10. package/dist/components/button/types/index.js +1 -0
  11. package/dist/components/error/ErrorBoundary.d.ts +25 -0
  12. package/dist/components/error/ErrorBoundary.d.ts.map +1 -0
  13. package/dist/components/error/ErrorBoundary.js +130 -0
  14. package/dist/components/error/index.d.ts +2 -0
  15. package/dist/components/error/index.d.ts.map +1 -0
  16. package/dist/components/error/index.js +1 -0
  17. package/dist/components/index.d.ts +6 -0
  18. package/dist/components/index.d.ts.map +1 -0
  19. package/dist/components/index.js +10 -0
  20. package/dist/components/loading/GlobalLoading.d.ts +12 -0
  21. package/dist/components/loading/GlobalLoading.d.ts.map +1 -0
  22. package/dist/components/loading/GlobalLoading.js +84 -0
  23. package/dist/components/loading/index.d.ts +2 -0
  24. package/dist/components/loading/index.d.ts.map +1 -0
  25. package/dist/components/loading/index.js +1 -0
  26. package/dist/components/modal/ModalContainer.d.ts +8 -0
  27. package/dist/components/modal/ModalContainer.d.ts.map +1 -0
  28. package/dist/components/modal/ModalContainer.js +161 -0
  29. package/dist/components/modal/ModalContext.d.ts +43 -0
  30. package/dist/components/modal/ModalContext.d.ts.map +1 -0
  31. package/dist/components/modal/ModalContext.js +78 -0
  32. package/dist/components/modal/index.d.ts +4 -0
  33. package/dist/components/modal/index.d.ts.map +1 -0
  34. package/dist/components/modal/index.js +2 -0
  35. package/dist/components/toast/ToastContainer.d.ts +12 -0
  36. package/dist/components/toast/ToastContainer.d.ts.map +1 -0
  37. package/dist/components/toast/ToastContainer.js +125 -0
  38. package/dist/components/toast/ToastContext.d.ts +40 -0
  39. package/dist/components/toast/ToastContext.d.ts.map +1 -0
  40. package/dist/components/toast/ToastContext.js +56 -0
  41. package/dist/components/toast/index.d.ts +4 -0
  42. package/dist/components/toast/index.d.ts.map +1 -0
  43. package/dist/components/toast/index.js +2 -0
  44. package/dist/hooks/index.d.ts +11 -0
  45. package/dist/hooks/index.d.ts.map +1 -0
  46. package/dist/hooks/index.js +17 -0
  47. package/dist/hooks/use-auth.d.ts +38 -0
  48. package/dist/hooks/use-auth.d.ts.map +1 -0
  49. package/dist/hooks/use-auth.js +117 -0
  50. package/dist/hooks/use-error-notification.d.ts +29 -0
  51. package/dist/hooks/use-error-notification.d.ts.map +1 -0
  52. package/dist/hooks/use-error-notification.js +91 -0
  53. package/dist/hooks/use-global-loading.d.ts +16 -0
  54. package/dist/hooks/use-global-loading.d.ts.map +1 -0
  55. package/dist/hooks/use-global-loading.js +72 -0
  56. package/dist/hooks/use-initialize.d.ts +26 -0
  57. package/dist/hooks/use-initialize.d.ts.map +1 -0
  58. package/dist/hooks/use-initialize.js +104 -0
  59. package/dist/hooks/use-modal.d.ts +39 -0
  60. package/dist/hooks/use-modal.d.ts.map +1 -0
  61. package/dist/hooks/use-modal.js +83 -0
  62. package/dist/hooks/use-navigate.d.ts +34 -0
  63. package/dist/hooks/use-navigate.d.ts.map +1 -0
  64. package/dist/hooks/use-navigate.js +89 -0
  65. package/dist/hooks/use-track-history.d.ts +33 -0
  66. package/dist/hooks/use-track-history.d.ts.map +1 -0
  67. package/dist/hooks/use-track-history.js +150 -0
  68. package/dist/index.d.ts +12 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +17 -0
  71. package/dist/network/axios-factory.d.ts +61 -0
  72. package/dist/network/axios-factory.d.ts.map +1 -0
  73. package/dist/network/axios-factory.js +119 -0
  74. package/dist/network/index.d.ts +5 -0
  75. package/dist/network/index.d.ts.map +1 -0
  76. package/dist/network/index.js +4 -0
  77. package/dist/network/supabase-axios.d.ts +62 -0
  78. package/dist/network/supabase-axios.d.ts.map +1 -0
  79. package/dist/network/supabase-axios.js +74 -0
  80. package/dist/store/index.d.ts +2 -0
  81. package/dist/store/index.d.ts.map +1 -0
  82. package/dist/store/index.js +1 -0
  83. package/dist/store/store-access.d.ts +48 -0
  84. package/dist/store/store-access.d.ts.map +1 -0
  85. package/dist/store/store-access.js +131 -0
  86. package/dist/types/index.d.ts +58 -0
  87. package/dist/types/index.d.ts.map +1 -0
  88. package/dist/types/index.js +5 -0
  89. package/dist/types/service.d.ts +17 -0
  90. package/dist/types/service.d.ts.map +1 -0
  91. package/dist/types/service.js +31 -0
  92. package/dist/utils/index.d.ts +2 -0
  93. package/dist/utils/index.d.ts.map +1 -0
  94. package/dist/utils/index.js +1 -0
  95. package/dist/utils/storage.d.ts +27 -0
  96. package/dist/utils/storage.d.ts.map +1 -0
  97. package/dist/utils/storage.js +78 -0
  98. package/package.json +27 -0
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Auth Hooks - KOMCA 패턴
3
+ * 로그인, 로그아웃, 토큰 갱신
4
+ */
5
+ import { useCallback } from 'react';
6
+ import { getHostStore, dispatchToHost } from '../store/store-access';
7
+ import { storage } from '../utils/storage';
8
+ /**
9
+ * 로그인 Hook
10
+ */
11
+ export function useLogin(loginApi) {
12
+ return useCallback(async (request) => {
13
+ try {
14
+ let response;
15
+ if (loginApi) {
16
+ // 실제 API 호출
17
+ response = await loginApi(request);
18
+ }
19
+ else {
20
+ // Mock 로그인 (개발용)
21
+ if (request.username === 'admin@test.com' && request.password === '1234') {
22
+ response = {
23
+ accessToken: `mock-token-${Date.now()}`,
24
+ user: {
25
+ id: '1',
26
+ name: '관리자',
27
+ email: request.username,
28
+ role: 'admin',
29
+ },
30
+ };
31
+ }
32
+ else {
33
+ throw new Error('아이디/비밀번호를 확인해주세요.');
34
+ }
35
+ }
36
+ // Store에 저장
37
+ dispatchToHost({ type: 'app/setAccessToken', payload: response.accessToken });
38
+ dispatchToHost({ type: 'app/setUser', payload: response.user });
39
+ // Storage에도 저장 (새로고침 대비)
40
+ storage.setAccessToken(response.accessToken);
41
+ storage.setUser(response.user);
42
+ console.log('[Login] 로그인 성공:', response.user.email);
43
+ return response;
44
+ }
45
+ catch (error) {
46
+ console.error('[Login] 로그인 실패:', error);
47
+ throw error;
48
+ }
49
+ }, [loginApi]);
50
+ }
51
+ /**
52
+ * 로그아웃 Hook
53
+ */
54
+ export function useLogout(logoutApi) {
55
+ return useCallback(async () => {
56
+ try {
57
+ // API 호출 (있는 경우)
58
+ if (logoutApi) {
59
+ await logoutApi();
60
+ }
61
+ // Store 초기화
62
+ dispatchToHost({ type: 'app/setAccessToken', payload: '' });
63
+ dispatchToHost({ type: 'app/setUser', payload: null });
64
+ dispatchToHost({ type: 'recentMenu/resetRecentMenu' });
65
+ // Storage 초기화
66
+ storage.clearAuth();
67
+ console.log('[Logout] 로그아웃 완료');
68
+ }
69
+ catch (error) {
70
+ console.error('[Logout] 로그아웃 실패:', error);
71
+ // 에러가 발생해도 로컬 상태는 초기화
72
+ storage.clearAuth();
73
+ throw error;
74
+ }
75
+ }, [logoutApi]);
76
+ }
77
+ /**
78
+ * 토큰 갱신 Hook
79
+ */
80
+ export function useTokenRefresh(refreshApi) {
81
+ return useCallback(async () => {
82
+ try {
83
+ if (!refreshApi) {
84
+ console.warn('[Token Refresh] refresh API가 설정되지 않았습니다.');
85
+ return null;
86
+ }
87
+ const newToken = await refreshApi();
88
+ if (newToken) {
89
+ // Store에 저장
90
+ dispatchToHost({ type: 'app/setAccessToken', payload: newToken });
91
+ storage.setAccessToken(newToken);
92
+ console.log('[Token Refresh] 토큰 갱신 성공');
93
+ return newToken;
94
+ }
95
+ return null;
96
+ }
97
+ catch (error) {
98
+ console.error('[Token Refresh] 토큰 갱신 실패:', error);
99
+ // 갱신 실패시 로그아웃 처리
100
+ dispatchToHost({ type: 'app/setAccessToken', payload: '' });
101
+ storage.setAccessToken('');
102
+ throw error;
103
+ }
104
+ }, [refreshApi]);
105
+ }
106
+ /**
107
+ * 인증 상태 확인 Hook
108
+ */
109
+ export function useAuthState() {
110
+ const store = getHostStore();
111
+ const state = store?.getState();
112
+ return {
113
+ isAuthenticated: !!state?.app?.accessToken,
114
+ user: state?.app?.user || null,
115
+ accessToken: state?.app?.accessToken || '',
116
+ };
117
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Error Notification Hook - KOMCA 패턴
3
+ * API 에러 발생시 자동 알림
4
+ */
5
+ import { ErrorDetail } from '../network/axios-factory';
6
+ export interface ErrorEvent {
7
+ errorDetails: ErrorDetail[];
8
+ }
9
+ /**
10
+ * 에러 이벤트 발생
11
+ */
12
+ export declare function dispatchErrorEvent(errorDetails: ErrorDetail[]): void;
13
+ /**
14
+ * 에러 알림 Hook
15
+ */
16
+ export declare function useErrorNotification(onError?: (errorDetails: ErrorDetail[]) => void): void;
17
+ /**
18
+ * 에러 메시지 포맷팅
19
+ */
20
+ export declare function formatErrorDetails(errorDetails: ErrorDetail[]): string;
21
+ /**
22
+ * Custom Event 유틸리티
23
+ */
24
+ export declare const customEvents: {
25
+ dispatchError: typeof dispatchErrorEvent;
26
+ dispatchSearch: (id?: string) => void;
27
+ onSearch: (callback: (id?: string) => void) => () => void;
28
+ };
29
+ //# sourceMappingURL=use-error-notification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-error-notification.d.ts","sourceRoot":"","sources":["../../src/hooks/use-error-notification.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAMvD,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,WAAW,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,WAAW,EAAE,QAK7D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,KAAK,IAAI,QA4BhD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,MAAM,CAuBtE;AAED;;GAEG;AACH,eAAO,MAAM,YAAY;;0BAKD,MAAM;yBAMP,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI;CAO3C,CAAC"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Error Notification Hook - KOMCA 패턴
3
+ * API 에러 발생시 자동 알림
4
+ */
5
+ import { useEffect } from 'react';
6
+ // 에러 이벤트 이름
7
+ const ERROR_EVENT_NAME = 'mfa:api-error';
8
+ /**
9
+ * 에러 이벤트 발생
10
+ */
11
+ export function dispatchErrorEvent(errorDetails) {
12
+ const event = new CustomEvent(ERROR_EVENT_NAME, {
13
+ detail: { errorDetails },
14
+ });
15
+ window.dispatchEvent(event);
16
+ }
17
+ /**
18
+ * 에러 알림 Hook
19
+ */
20
+ export function useErrorNotification(onError) {
21
+ useEffect(() => {
22
+ const handleError = (event) => {
23
+ const { errorDetails } = event.detail;
24
+ if (onError) {
25
+ onError(errorDetails);
26
+ }
27
+ else {
28
+ // 기본 에러 처리
29
+ const messages = errorDetails.map((detail) => {
30
+ if (detail.field) {
31
+ return `[${detail.field}] ${detail.message || detail.code}`;
32
+ }
33
+ return detail.message || detail.code;
34
+ });
35
+ console.error('[API Error]', messages.join('\n'));
36
+ // alert(messages.join('\n'));
37
+ }
38
+ };
39
+ window.addEventListener(ERROR_EVENT_NAME, handleError);
40
+ return () => {
41
+ window.removeEventListener(ERROR_EVENT_NAME, handleError);
42
+ };
43
+ }, [onError]);
44
+ }
45
+ /**
46
+ * 에러 메시지 포맷팅
47
+ */
48
+ export function formatErrorDetails(errorDetails) {
49
+ return errorDetails
50
+ .map((detail) => {
51
+ switch (detail.code) {
52
+ case 'NotBlank':
53
+ return `${detail.field || '필드'}은(는) 필수 입력입니다.`;
54
+ case 'NotNull':
55
+ return `${detail.field || '필드'}은(는) 필수 입력입니다.`;
56
+ case 'Pattern':
57
+ return `${detail.field || '필드'} 형식이 올바르지 않습니다.`;
58
+ case 'Min':
59
+ return `${detail.field || '값'}이 최소값보다 작습니다.`;
60
+ case 'Max':
61
+ return `${detail.field || '값'}이 최대값을 초과했습니다.`;
62
+ case 'Size':
63
+ return `${detail.field || '값'} 길이가 허용 범위를 벗어났습니다.`;
64
+ case 'TYPE_MISMATCH':
65
+ return `${detail.field || '필드'} 타입이 올바르지 않습니다.`;
66
+ default:
67
+ return detail.message || '알 수 없는 오류가 발생했습니다.';
68
+ }
69
+ })
70
+ .join('\n');
71
+ }
72
+ /**
73
+ * Custom Event 유틸리티
74
+ */
75
+ export const customEvents = {
76
+ // 에러 이벤트 발생
77
+ dispatchError: dispatchErrorEvent,
78
+ // 검색 이벤트 발생
79
+ dispatchSearch: (id) => {
80
+ const event = new CustomEvent('mfa:search', { detail: { id } });
81
+ window.dispatchEvent(event);
82
+ },
83
+ // 검색 이벤트 구독
84
+ onSearch: (callback) => {
85
+ const handler = (event) => {
86
+ callback(event.detail.id);
87
+ };
88
+ window.addEventListener('mfa:search', handler);
89
+ return () => window.removeEventListener('mfa:search', handler);
90
+ },
91
+ };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Global Loading Hook - KOMCA 패턴
3
+ * API 호출 시 전역 로딩 표시
4
+ */
5
+ /**
6
+ * Global Loading Title 설정
7
+ */
8
+ export declare function useShowGlobalLoading(): <T>(promise: Promise<T>, title?: string) => Promise<T>;
9
+ /**
10
+ * Loading 상태 직접 제어
11
+ */
12
+ export declare function useLoadingControl(): {
13
+ showLoading: (title?: string) => void;
14
+ hideLoading: () => void;
15
+ };
16
+ //# sourceMappingURL=use-global-loading.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-global-loading.d.ts","sourceRoot":"","sources":["../../src/hooks/use-global-loading.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH;;GAEG;AACH,wBAAgB,oBAAoB,KACd,CAAC,WAAW,OAAO,CAAC,CAAC,CAAC,UAAU,MAAM,KAAG,OAAO,CAAC,CAAC,CAAC,CA6BxE;AAED;;GAEG;AACH,wBAAgB,iBAAiB;0BACU,MAAM;;EA+BhD"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Global Loading Hook - KOMCA 패턴
3
+ * API 호출 시 전역 로딩 표시
4
+ */
5
+ import { useCallback } from 'react';
6
+ import { getHostStore } from '../store/store-access';
7
+ /**
8
+ * Global Loading Title 설정
9
+ */
10
+ export function useShowGlobalLoading() {
11
+ return useCallback((promise, title) => {
12
+ const store = getHostStore();
13
+ if (store) {
14
+ // 로딩 시작
15
+ store.dispatch({
16
+ type: 'app/setGlobalLoadingTitle',
17
+ payload: title || '처리 중...',
18
+ });
19
+ store.dispatch({
20
+ type: 'app/setLoading',
21
+ payload: true,
22
+ });
23
+ }
24
+ return promise.finally(() => {
25
+ if (store) {
26
+ // 로딩 종료
27
+ store.dispatch({
28
+ type: 'app/setLoading',
29
+ payload: false,
30
+ });
31
+ store.dispatch({
32
+ type: 'app/setGlobalLoadingTitle',
33
+ payload: '',
34
+ });
35
+ }
36
+ });
37
+ }, []);
38
+ }
39
+ /**
40
+ * Loading 상태 직접 제어
41
+ */
42
+ export function useLoadingControl() {
43
+ const showLoading = useCallback((title) => {
44
+ const store = getHostStore();
45
+ if (store) {
46
+ store.dispatch({
47
+ type: 'app/setLoading',
48
+ payload: true,
49
+ });
50
+ if (title) {
51
+ store.dispatch({
52
+ type: 'app/setGlobalLoadingTitle',
53
+ payload: title,
54
+ });
55
+ }
56
+ }
57
+ }, []);
58
+ const hideLoading = useCallback(() => {
59
+ const store = getHostStore();
60
+ if (store) {
61
+ store.dispatch({
62
+ type: 'app/setLoading',
63
+ payload: false,
64
+ });
65
+ store.dispatch({
66
+ type: 'app/setGlobalLoadingTitle',
67
+ payload: '',
68
+ });
69
+ }
70
+ }, []);
71
+ return { showLoading, hideLoading };
72
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Initialize Hook - KOMCA 패턴
3
+ * 앱 시작시 초기화 (토큰 갱신, 사용자 정보 로드)
4
+ */
5
+ import { User } from '../types';
6
+ export interface InitializeOptions {
7
+ refreshToken?: () => Promise<string | null>;
8
+ fetchUserInfo?: () => Promise<User | null>;
9
+ onInitialized?: () => void;
10
+ onError?: (error: Error) => void;
11
+ }
12
+ /**
13
+ * 앱 초기화 Hook
14
+ */
15
+ export declare function useInitialize(options?: InitializeOptions): {
16
+ initialized: boolean;
17
+ loading: boolean;
18
+ error: Error | null;
19
+ };
20
+ /**
21
+ * 간단한 초기화 Hook (토큰/사용자 정보 복구만)
22
+ */
23
+ export declare function useSimpleInitialize(): {
24
+ initialized: boolean;
25
+ };
26
+ //# sourceMappingURL=use-initialize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-initialize.d.ts","sourceRoot":"","sources":["../../src/hooks/use-initialize.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAGhC,MAAM,WAAW,iBAAiB;IAEhC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAE5C,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAE3C,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAE3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,iBAAsB;;;;EAyE5D;AAED;;GAEG;AACH,wBAAgB,mBAAmB;;EA4BlC"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Initialize Hook - KOMCA 패턴
3
+ * 앱 시작시 초기화 (토큰 갱신, 사용자 정보 로드)
4
+ */
5
+ import { useEffect, useState } from 'react';
6
+ import { dispatchToHost } from '../store/store-access';
7
+ import { storage } from '../utils/storage';
8
+ /**
9
+ * 앱 초기화 Hook
10
+ */
11
+ export function useInitialize(options = {}) {
12
+ const [initialized, setInitialized] = useState(false);
13
+ const [loading, setLoading] = useState(true);
14
+ const [error, setError] = useState(null);
15
+ useEffect(() => {
16
+ const initialize = async () => {
17
+ try {
18
+ setLoading(true);
19
+ // 1. Storage에서 기존 토큰 복구
20
+ const savedToken = storage.getAccessToken();
21
+ const savedUser = storage.getUser();
22
+ if (savedToken) {
23
+ // Store에 복구
24
+ dispatchToHost({ type: 'app/setAccessToken', payload: savedToken });
25
+ if (savedUser) {
26
+ dispatchToHost({ type: 'app/setUser', payload: savedUser });
27
+ }
28
+ // 2. 토큰 갱신 시도 (옵션)
29
+ if (options.refreshToken) {
30
+ try {
31
+ const newToken = await options.refreshToken();
32
+ if (newToken) {
33
+ dispatchToHost({ type: 'app/setAccessToken', payload: newToken });
34
+ storage.setAccessToken(newToken);
35
+ console.log('[Initialize] 토큰 갱신 성공');
36
+ // 3. 사용자 정보 갱신 (옵션)
37
+ if (options.fetchUserInfo) {
38
+ const userInfo = await options.fetchUserInfo();
39
+ if (userInfo) {
40
+ dispatchToHost({ type: 'app/setUser', payload: userInfo });
41
+ storage.setUser(userInfo);
42
+ console.log('[Initialize] 사용자 정보 갱신:', userInfo.email);
43
+ }
44
+ }
45
+ }
46
+ }
47
+ catch (refreshError) {
48
+ console.warn('[Initialize] 토큰 갱신 실패, 기존 토큰 사용');
49
+ }
50
+ }
51
+ }
52
+ // 4. Recent Menu 복구
53
+ const savedRecentMenu = storage.getRecentMenu();
54
+ if (savedRecentMenu.length > 0) {
55
+ dispatchToHost({
56
+ type: 'recentMenu/setRecentMenu',
57
+ payload: { list: savedRecentMenu },
58
+ });
59
+ }
60
+ setInitialized(true);
61
+ options.onInitialized?.();
62
+ console.log('[Initialize] 앱 초기화 완료');
63
+ }
64
+ catch (err) {
65
+ const error = err instanceof Error ? err : new Error('초기화 실패');
66
+ setError(error);
67
+ options.onError?.(error);
68
+ console.error('[Initialize] 초기화 에러:', error);
69
+ }
70
+ finally {
71
+ setLoading(false);
72
+ }
73
+ };
74
+ initialize();
75
+ }, []);
76
+ return { initialized, loading, error };
77
+ }
78
+ /**
79
+ * 간단한 초기화 Hook (토큰/사용자 정보 복구만)
80
+ */
81
+ export function useSimpleInitialize() {
82
+ const [initialized, setInitialized] = useState(false);
83
+ useEffect(() => {
84
+ // Storage에서 복구
85
+ const savedToken = storage.getAccessToken();
86
+ const savedUser = storage.getUser();
87
+ if (savedToken) {
88
+ dispatchToHost({ type: 'app/setAccessToken', payload: savedToken });
89
+ }
90
+ if (savedUser) {
91
+ dispatchToHost({ type: 'app/setUser', payload: savedUser });
92
+ }
93
+ // Recent Menu 복구
94
+ const savedRecentMenu = storage.getRecentMenu();
95
+ if (savedRecentMenu.length > 0) {
96
+ dispatchToHost({
97
+ type: 'recentMenu/setRecentMenu',
98
+ payload: { list: savedRecentMenu },
99
+ });
100
+ }
101
+ setInitialized(true);
102
+ }, []);
103
+ return { initialized };
104
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Modal Hooks - KOMCA 패턴
3
+ * Alert, Confirm 모달 관리
4
+ */
5
+ export interface ModalHookOptions {
6
+ title?: string;
7
+ message: string;
8
+ confirmText?: string;
9
+ cancelText?: string;
10
+ }
11
+ export interface AlertModalResult {
12
+ isOpen: boolean;
13
+ options: ModalHookOptions | null;
14
+ show: (options: ModalHookOptions | string) => Promise<void>;
15
+ close: () => void;
16
+ }
17
+ export interface ConfirmModalResult {
18
+ isOpen: boolean;
19
+ options: ModalHookOptions | null;
20
+ show: (options: ModalHookOptions | string) => Promise<boolean>;
21
+ close: (confirmed: boolean) => void;
22
+ }
23
+ /**
24
+ * Alert 모달 Hook
25
+ */
26
+ export declare function useAlertModal(): AlertModalResult;
27
+ /**
28
+ * Confirm 모달 Hook
29
+ */
30
+ export declare function useConfirmModal(): ConfirmModalResult;
31
+ /**
32
+ * 비동기 Alert 모달 - 간편 사용
33
+ */
34
+ export declare function useAsyncAlertModal(): (message: string, title?: string) => Promise<void>;
35
+ /**
36
+ * 비동기 Confirm 모달 - 간편 사용
37
+ */
38
+ export declare function useAsyncConfirmModal(): (message: string, title?: string) => Promise<boolean>;
39
+ //# sourceMappingURL=use-modal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-modal.d.ts","sourceRoot":"","sources":["../../src/hooks/use-modal.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAGD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAGD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/D,KAAK,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;CACrC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,gBAAgB,CA4BhD;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,kBAAkB,CA4BpD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,cACH,MAAM,UAAU,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC,CAOpE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,cACL,MAAM,UAAU,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC,CAOvE"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Modal Hooks - KOMCA 패턴
3
+ * Alert, Confirm 모달 관리
4
+ */
5
+ import { useCallback, useState } from 'react';
6
+ /**
7
+ * Alert 모달 Hook
8
+ */
9
+ export function useAlertModal() {
10
+ const [isOpen, setIsOpen] = useState(false);
11
+ const [options, setOptions] = useState(null);
12
+ const [resolver, setResolver] = useState(null);
13
+ const show = useCallback((opts) => {
14
+ const modalOptions = typeof opts === 'string'
15
+ ? { message: opts }
16
+ : opts;
17
+ setOptions(modalOptions);
18
+ setIsOpen(true);
19
+ return new Promise((resolve) => {
20
+ setResolver(() => resolve);
21
+ });
22
+ }, []);
23
+ const close = useCallback(() => {
24
+ setIsOpen(false);
25
+ setOptions(null);
26
+ if (resolver) {
27
+ resolver();
28
+ setResolver(null);
29
+ }
30
+ }, [resolver]);
31
+ return { isOpen, options, show, close };
32
+ }
33
+ /**
34
+ * Confirm 모달 Hook
35
+ */
36
+ export function useConfirmModal() {
37
+ const [isOpen, setIsOpen] = useState(false);
38
+ const [options, setOptions] = useState(null);
39
+ const [resolver, setResolver] = useState(null);
40
+ const show = useCallback((opts) => {
41
+ const modalOptions = typeof opts === 'string'
42
+ ? { message: opts, confirmText: '확인', cancelText: '취소' }
43
+ : { confirmText: '확인', cancelText: '취소', ...opts };
44
+ setOptions(modalOptions);
45
+ setIsOpen(true);
46
+ return new Promise((resolve) => {
47
+ setResolver(() => resolve);
48
+ });
49
+ }, []);
50
+ const close = useCallback((confirmed) => {
51
+ setIsOpen(false);
52
+ setOptions(null);
53
+ if (resolver) {
54
+ resolver(confirmed);
55
+ setResolver(null);
56
+ }
57
+ }, [resolver]);
58
+ return { isOpen, options, show, close };
59
+ }
60
+ /**
61
+ * 비동기 Alert 모달 - 간편 사용
62
+ */
63
+ export function useAsyncAlertModal() {
64
+ return useCallback((message, title) => {
65
+ return new Promise((resolve) => {
66
+ // 브라우저 기본 alert 사용 (커스텀 모달로 교체 가능)
67
+ alert(title ? `${title}\n\n${message}` : message);
68
+ resolve();
69
+ });
70
+ }, []);
71
+ }
72
+ /**
73
+ * 비동기 Confirm 모달 - 간편 사용
74
+ */
75
+ export function useAsyncConfirmModal() {
76
+ return useCallback((message, title) => {
77
+ return new Promise((resolve) => {
78
+ // 브라우저 기본 confirm 사용 (커스텀 모달로 교체 가능)
79
+ const result = confirm(title ? `${title}\n\n${message}` : message);
80
+ resolve(result);
81
+ });
82
+ }, []);
83
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * MFA Navigate Hook - KOMCA 패턴
3
+ * 서비스 인식 네비게이션
4
+ */
5
+ import { NavigateOptions } from 'react-router-dom';
6
+ import { ServiceType } from '../types/service';
7
+ export interface MfaNavigateOptions extends NavigateOptions {
8
+ service?: ServiceType;
9
+ }
10
+ /**
11
+ * MFA Navigate Hook
12
+ * 서비스 prefix를 자동으로 처리하는 네비게이션
13
+ */
14
+ export declare function useMfaNavigate(): (to: string | {
15
+ pathname?: string;
16
+ search?: string;
17
+ hash?: string;
18
+ }, options?: MfaNavigateOptions) => void;
19
+ /**
20
+ * 현재 위치 정보 Hook
21
+ */
22
+ export declare function useCurrentLocation(): {
23
+ pathname: string;
24
+ search: string;
25
+ hash: string;
26
+ state: any;
27
+ service: ServiceType | null;
28
+ isHostApp: boolean;
29
+ };
30
+ /**
31
+ * 경로 빌더
32
+ */
33
+ export declare function buildPath(pathname: string, service?: ServiceType, params?: Record<string, string>): string;
34
+ //# sourceMappingURL=use-navigate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-navigate.d.ts","sourceRoot":"","sources":["../../src/hooks/use-navigate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAA4B,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE7E,OAAO,EACL,WAAW,EAKZ,MAAM,kBAAkB,CAAC;AAG1B,MAAM,WAAW,kBAAmB,SAAQ,eAAe;IACzD,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,cAAc,SAUtB,MAAM,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,YACxD,kBAAkB,UA4C/B;AAED;;GAEG;AACH,wBAAgB,kBAAkB;;;;;;;EAWjC;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,WAAW,EACrB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,MAAM,CAkBR"}