sales-frontend-features 0.0.23 → 0.0.25
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.
- package/dist/index.cjs +16 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +16 -14
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -104,24 +104,24 @@ var createWebviewClientSession = async () => {
|
|
|
104
104
|
businessWorkDivisionCode: salesFrontendUtils.getBusinessWorkDivisionCode()
|
|
105
105
|
};
|
|
106
106
|
};
|
|
107
|
-
var
|
|
107
|
+
var getFpUserInfo = async () => {
|
|
108
108
|
try {
|
|
109
109
|
const { isSuccess, data } = await method.getUserProfile();
|
|
110
110
|
if (isSuccess && data) {
|
|
111
|
-
console.log("[useSetupClientSession] \uD504\uB85C\uD544 \uB85C\uB4DC \uC131\uACF5");
|
|
111
|
+
console.log("[useSetupClientSession-getFpUserInfo] \uD504\uB85C\uD544 \uB85C\uB4DC \uC131\uACF5");
|
|
112
112
|
return data;
|
|
113
113
|
}
|
|
114
|
-
console.warn("[
|
|
114
|
+
console.warn("[useSetupClientSession-getFpUserInfo] \uD504\uB85C\uD544 \uB85C\uB4DC \uC2E4\uD328: \uC751\uB2F5 \uC5C6\uC74C");
|
|
115
115
|
return null;
|
|
116
116
|
} catch (error) {
|
|
117
|
-
console.error("[
|
|
117
|
+
console.error("[useSetupClientSession-getFpUserInfo] \uD504\uB85C\uD544 \uB85C\uB4DC \uC2E4\uD328:", error);
|
|
118
118
|
return null;
|
|
119
119
|
}
|
|
120
120
|
};
|
|
121
121
|
|
|
122
122
|
// src/client-session/use-setup-client-session.tsx
|
|
123
123
|
var useSetupClientSession = () => {
|
|
124
|
-
const { isInitialized, isLoggedIn } = salesFrontendStores.useClientSession();
|
|
124
|
+
const { isInitialized, isLoggedIn, userType } = salesFrontendStores.useClientSession();
|
|
125
125
|
const setClientSession = salesFrontendStores.useSetClientSession();
|
|
126
126
|
react.useEffect(() => {
|
|
127
127
|
if (isInitialized) {
|
|
@@ -150,15 +150,17 @@ var useSetupClientSession = () => {
|
|
|
150
150
|
if (!isInitialized || !isLoggedIn) {
|
|
151
151
|
return;
|
|
152
152
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
153
|
+
if (userType === "FP") {
|
|
154
|
+
const loadUserInfo = async () => {
|
|
155
|
+
console.log("[useSetupClientSession] \uC0AC\uC6A9\uC790 \uD504\uB85C\uD544 \uB85C\uB4DC \uC2DC\uC791...");
|
|
156
|
+
const userInfo = await getFpUserInfo();
|
|
157
|
+
if (userInfo) {
|
|
158
|
+
setClientSession(userInfo);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
loadUserInfo();
|
|
162
|
+
}
|
|
163
|
+
}, [isInitialized, isLoggedIn, userType, setClientSession]);
|
|
162
164
|
return isInitialized ?? false;
|
|
163
165
|
};
|
|
164
166
|
var ClientSessionProvider = ({ children, loadingComponent = null }) => {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/navigation/history-back-handler.tsx","../src/client-session/client-session-utils.ts","../src/client-session/use-setup-client-session.tsx","../src/client-session/client-session-provider.tsx"],"names":["isWebView","Bridge","getFormFactorFromUserAgent","getCookie","getOrCreateDeviceId","getBrowserName","getBrowserVersion","getOSName","getOSVersion","getDeviceModel","isSalesPortal","getBusinessWorkDivisionCode","isFpPlannerApp","getUserProfile","useClientSession","useSetClientSession","useEffect"],"mappings":"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","file":"index.cjs","sourcesContent":["import { Bridge } from 'sales-frontend-bridge';\nimport { isWebView } from 'sales-frontend-utils';\n\nexport const ENTRY_PATH_KEY = 'ENTRY_PATH';\n\nexport interface NativeEntry {\n path: string;\n timestamp: number;\n}\n\n/**\n * 뒤로가기 핸들러\n * 네이티브 앱 기본: 뒤로가다가 첫 페이지일 경우 웹뷰 닫기\n */\nexport const handleHistoryBack = () => {\n // 순수 웹인 경우 일반 뒤로가기\n if (!isWebView()) {\n window.history.back();\n\n return;\n }\n\n const entryStr = sessionStorage.getItem(ENTRY_PATH_KEY);\n if (!entryStr) {\n window.history.back();\n\n return;\n }\n\n try {\n const entry: NativeEntry = JSON.parse(entryStr);\n const currentPath = window.location.pathname + window.location.search;\n const timeSinceEntry = Date.now() - entry.timestamp;\n\n // 진입 경로이고 + 진입 후 5초 이내\n if (currentPath === entry.path && timeSinceEntry >= 1) {\n console.log('[handleBack] 진입 페이지 - 웹뷰 닫기');\n Bridge.native.closeWeb();\n } else {\n console.log('[handleBack] 일반 뒤로가기');\n window.history.back();\n }\n } catch (error) {\n console.error('[handleBack] Entry 파싱 실패:', error);\n window.history.back();\n }\n};\n\nexport const setEntryToSessionStorage = () => {\n const entry: NativeEntry = {\n path: window.location.pathname + window.location.search,\n timestamp: Date.now()\n };\n sessionStorage.setItem(ENTRY_PATH_KEY, JSON.stringify(entry));\n};\n","import { getUserProfile } from 'sales-frontend-api/method';\nimport { Bridge } from 'sales-frontend-bridge';\nimport {\n getCookie,\n getOrCreateDeviceId,\n getBrowserName,\n getBrowserVersion,\n getOSName,\n getOSVersion,\n getDeviceModel,\n isSalesPortal,\n getFormFactorFromUserAgent,\n isFpPlannerApp,\n getBusinessWorkDivisionCode\n} from 'sales-frontend-utils';\n\nimport type { ClientSession } from 'sales-frontend-stores';\n\n/**\n * URL 경로의 두 번째 세그먼트에서 폼팩터를 추출하거나 User Agent로 감지\n * @param pathname - URL 경로 (예: /aaa/mobile, /aaa/tablet, /aaa/pc)\n * @returns 'mobile' | 'tablet' | 'pc'\n */\nconst getFormFactor = (): 'phone' | 'tablet' | 'pc' | undefined => {\n const { pathname } = location;\n\n // pathname이 제공된 경우 URL에서 추출 시도\n if (pathname) {\n const segments = pathname.split('/').filter(Boolean);\n\n // 두 번째 세그먼트 확인 (인덱스 1)\n if (segments.length >= 2) {\n const secondSegment = segments[1]?.toLowerCase();\n\n if (secondSegment === 'mobile') {\n return 'phone';\n }\n if (secondSegment === 'tablet') {\n return 'tablet';\n }\n if (secondSegment === 'pc') {\n return 'pc';\n }\n }\n }\n\n // URL에 없으면 User Agent로 감지\n return getFormFactorFromUserAgent(navigator.userAgent);\n};\n\n/**\n * 순수 웹 상태값 초기화\n * @returns\n */\nexport const createPureWebClientSession = async (): Promise<ClientSession> => {\n const hasAccessToken = !!getCookie('accessToken');\n\n return {\n isInitialized: true,\n isLoggedIn: hasAccessToken,\n isWebView: false,\n acceptLanguage: navigator.language || 'ko',\n formFactor: getFormFactor(),\n deviceId: getOrCreateDeviceId(),\n appVersion: `${getBrowserName(navigator.userAgent)} ${getBrowserVersion(navigator.userAgent)}`,\n loginType: 'web-login',\n platformName: getOSName(navigator.userAgent),\n platformVersion: getOSVersion(navigator.userAgent),\n deviceModel: getDeviceModel(),\n loginChannel: isSalesPortal() ? 'HMP' : 'WEB',\n businessWorkDivisionCode: getBusinessWorkDivisionCode()\n };\n};\n\n/**\n * 웹뷰 상태값 초기화\n * @returns\n */\nexport const createWebviewClientSession = async (): Promise<ClientSession> => {\n const [appInfo, accessToken] = await Promise.allSettled([\n Bridge.native.getAppInfo(),\n isFpPlannerApp()\n ? Promise.resolve(getCookie('accessToken'))\n : Bridge.native.getAccessToken().then((res) => res.accessToken)\n ]);\n\n const appInfoData = appInfo.status === 'fulfilled' ? appInfo.value : null;\n const isLoggedIn = accessToken.status === 'fulfilled' ? !!accessToken.value : false;\n\n const formFactor =\n appInfoData?.['X-Channel-FormFactor']?.toLowerCase() ?? getCookie('formFactor')?.toLowerCase() ?? getFormFactor();\n\n const loginChannel = appInfoData?.['X-Channel-LoginChannel'] ?? getCookie('loginChannel') ?? 'DSP';\n\n return {\n isInitialized: true,\n isLoggedIn,\n isWebView: true,\n acceptLanguage: appInfoData?.['Accept-Language'] ?? 'ko',\n formFactor: formFactor as 'tablet' | 'phone' | 'pc' | undefined,\n deviceId: appInfoData?.['X-Channel-DeviceId'] ?? getCookie('deviceId'),\n appVersion: appInfoData?.['X-Channel-AppVersion'] ?? getCookie('appVersion'),\n loginType: appInfoData?.['X-Channel-LoginType'] ?? getCookie('loginType'),\n platformName: appInfoData?.['X-Channel-PlatformName'] ?? getCookie('platformName'),\n platformVersion: appInfoData?.['X-Channel-PlatformVersion'] ?? getCookie('platformVersion'),\n deviceModel: appInfoData?.['X-Channel-DeviceModel'] ?? getCookie('deviceModel'),\n loginChannel: loginChannel as 'DSP' | 'MSP',\n businessWorkDivisionCode: getBusinessWorkDivisionCode()\n };\n};\n\nexport const getLoginUserInfo = async () => {\n try {\n const { isSuccess, data } = await getUserProfile();\n\n if (isSuccess && data) {\n console.log('[useSetupClientSession] 프로필 로드 성공');\n\n return data;\n }\n\n console.warn('[getLoginUserInfo] 프로필 로드 실패: 응답 없음');\n\n return null;\n } catch (error) {\n console.error('[getLoginUserInfo] 프로필 로드 실패:', error);\n\n return null;\n }\n};\n","import { useEffect } from 'react';\n\nimport { useClientSession, useSetClientSession } from 'sales-frontend-stores';\nimport { isWebView } from 'sales-frontend-utils';\n\nimport { setEntryToSessionStorage } from '../navigation/history-back-handler';\n\nimport { createWebviewClientSession, createPureWebClientSession, getLoginUserInfo } from './client-session-utils';\n/**\n * 앱 시작 시 ClientSession을 플랫폼(웹뷰, 순수 웹)에 맞게 자동 설정하는 훅\n *\n * @returns {boolean} 초기화 완료 여부\n */\nexport const useSetupClientSession = (): boolean => {\n const { isInitialized, isLoggedIn } = useClientSession();\n const setClientSession = useSetClientSession();\n\n useEffect(() => {\n if (isInitialized) {\n console.log('[useSetupClientSession] Already initialized');\n\n return;\n }\n\n const initialize = async () => {\n try {\n console.log('[useSetupClientSession] 초기화 시작...');\n\n if (isWebView()) {\n console.log('[useSetupClientSession] 웹뷰 환경 감지');\n // 최초 진입 경로 저장\n setEntryToSessionStorage();\n\n setClientSession(await createWebviewClientSession());\n } else {\n console.log('[useSetupClientSession] 순수 웹 환경 감지');\n setClientSession(await createPureWebClientSession());\n }\n\n console.log('[useSetupClientSession] 기본 세션 설정 완료');\n } catch (error) {\n console.error('[useSetupClientSession] 초기화 실패:', error);\n }\n };\n\n // 기본 초기화\n initialize();\n }, [isInitialized, setClientSession]);\n\n useEffect(() => {\n if (!isInitialized || !isLoggedIn) {\n return;\n }\n\n const loadUserInfo = async () => {\n console.log('[useSetupClientSession] 사용자 프로필 로드 시작...');\n\n const userInfo = await getLoginUserInfo();\n if (userInfo) {\n setClientSession(userInfo);\n }\n };\n\n // 로그인 FP 사용자 불러오기\n loadUserInfo();\n }, [isInitialized, isLoggedIn, setClientSession]);\n\n // 초기화 완료 여부 반환\n return isInitialized ?? false;\n};\n","import { useSetupClientSession } from './use-setup-client-session';\n\ninterface ClientSessionProviderProps {\n children: React.ReactNode;\n /**\n * 초기화 중 표시할 로딩 컴포넌트\n */\n loadingComponent?: React.ReactNode;\n}\n\n/**\n * ClientSession 초기화를 담당하는 Provider 컴포넌트\n * 앱의 최상위에서 사용하여 플랫폼별 세션 정보를 자동으로 설정합니다.\n */\nexport const ClientSessionProvider = ({ children, loadingComponent = null }: ClientSessionProviderProps) => {\n const isInitialized = useSetupClientSession();\n\n // 초기화 완료 전까지 fallback 표시\n if (!isInitialized) {\n return <>{loadingComponent}</>;\n }\n\n return <>{children}</>;\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/navigation/history-back-handler.tsx","../src/client-session/client-session-utils.ts","../src/client-session/use-setup-client-session.tsx","../src/client-session/client-session-provider.tsx"],"names":["isWebView","Bridge","getFormFactorFromUserAgent","getCookie","getOrCreateDeviceId","getBrowserName","getBrowserVersion","getOSName","getOSVersion","getDeviceModel","isSalesPortal","getBusinessWorkDivisionCode","isFpPlannerApp","getUserProfile","useClientSession","useSetClientSession","useEffect"],"mappings":"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","file":"index.cjs","sourcesContent":["import { Bridge } from 'sales-frontend-bridge';\nimport { isWebView } from 'sales-frontend-utils';\n\nexport const ENTRY_PATH_KEY = 'ENTRY_PATH';\n\nexport interface NativeEntry {\n path: string;\n timestamp: number;\n}\n\n/**\n * 뒤로가기 핸들러\n * 네이티브 앱 기본: 뒤로가다가 첫 페이지일 경우 웹뷰 닫기\n */\nexport const handleHistoryBack = () => {\n // 순수 웹인 경우 일반 뒤로가기\n if (!isWebView()) {\n window.history.back();\n\n return;\n }\n\n const entryStr = sessionStorage.getItem(ENTRY_PATH_KEY);\n if (!entryStr) {\n window.history.back();\n\n return;\n }\n\n try {\n const entry: NativeEntry = JSON.parse(entryStr);\n const currentPath = window.location.pathname + window.location.search;\n const timeSinceEntry = Date.now() - entry.timestamp;\n\n // 진입 경로이고 + 진입 후 5초 이내\n if (currentPath === entry.path && timeSinceEntry >= 1) {\n console.log('[handleBack] 진입 페이지 - 웹뷰 닫기');\n Bridge.native.closeWeb();\n } else {\n console.log('[handleBack] 일반 뒤로가기');\n window.history.back();\n }\n } catch (error) {\n console.error('[handleBack] Entry 파싱 실패:', error);\n window.history.back();\n }\n};\n\nexport const setEntryToSessionStorage = () => {\n const entry: NativeEntry = {\n path: window.location.pathname + window.location.search,\n timestamp: Date.now()\n };\n sessionStorage.setItem(ENTRY_PATH_KEY, JSON.stringify(entry));\n};\n","import { getUserProfile } from 'sales-frontend-api/method';\nimport { Bridge } from 'sales-frontend-bridge';\nimport {\n getCookie,\n getOrCreateDeviceId,\n getBrowserName,\n getBrowserVersion,\n getOSName,\n getOSVersion,\n getDeviceModel,\n isSalesPortal,\n getFormFactorFromUserAgent,\n isFpPlannerApp,\n getBusinessWorkDivisionCode\n} from 'sales-frontend-utils';\n\nimport type { ClientSession } from 'sales-frontend-stores';\n\n/**\n * URL 경로의 두 번째 세그먼트에서 폼팩터를 추출하거나 User Agent로 감지\n * @param pathname - URL 경로 (예: /aaa/mobile, /aaa/tablet, /aaa/pc)\n * @returns 'mobile' | 'tablet' | 'pc'\n */\nconst getFormFactor = (): 'phone' | 'tablet' | 'pc' | undefined => {\n const { pathname } = location;\n\n // pathname이 제공된 경우 URL에서 추출 시도\n if (pathname) {\n const segments = pathname.split('/').filter(Boolean);\n\n // 두 번째 세그먼트 확인 (인덱스 1)\n if (segments.length >= 2) {\n const secondSegment = segments[1]?.toLowerCase();\n\n if (secondSegment === 'mobile') {\n return 'phone';\n }\n if (secondSegment === 'tablet') {\n return 'tablet';\n }\n if (secondSegment === 'pc') {\n return 'pc';\n }\n }\n }\n\n // URL에 없으면 User Agent로 감지\n return getFormFactorFromUserAgent(navigator.userAgent);\n};\n\n/**\n * 순수 웹 상태값 초기화\n * @returns\n */\nexport const createPureWebClientSession = async (): Promise<ClientSession> => {\n const hasAccessToken = !!getCookie('accessToken');\n\n return {\n isInitialized: true,\n isLoggedIn: hasAccessToken,\n isWebView: false,\n acceptLanguage: navigator.language || 'ko',\n formFactor: getFormFactor(),\n deviceId: getOrCreateDeviceId(),\n appVersion: `${getBrowserName(navigator.userAgent)} ${getBrowserVersion(navigator.userAgent)}`,\n loginType: 'web-login',\n platformName: getOSName(navigator.userAgent),\n platformVersion: getOSVersion(navigator.userAgent),\n deviceModel: getDeviceModel(),\n loginChannel: isSalesPortal() ? 'HMP' : 'WEB',\n businessWorkDivisionCode: getBusinessWorkDivisionCode()\n };\n};\n\n/**\n * 웹뷰 상태값 초기화\n * @returns\n */\nexport const createWebviewClientSession = async (): Promise<ClientSession> => {\n const [appInfo, accessToken] = await Promise.allSettled([\n Bridge.native.getAppInfo(),\n isFpPlannerApp()\n ? Promise.resolve(getCookie('accessToken'))\n : Bridge.native.getAccessToken().then((res) => res.accessToken)\n ]);\n\n const appInfoData = appInfo.status === 'fulfilled' ? appInfo.value : null;\n const isLoggedIn = accessToken.status === 'fulfilled' ? !!accessToken.value : false;\n\n const formFactor =\n appInfoData?.['X-Channel-FormFactor']?.toLowerCase() ?? getCookie('formFactor')?.toLowerCase() ?? getFormFactor();\n\n const loginChannel = appInfoData?.['X-Channel-LoginChannel'] ?? getCookie('loginChannel') ?? 'DSP';\n\n return {\n isInitialized: true,\n isLoggedIn,\n isWebView: true,\n acceptLanguage: appInfoData?.['Accept-Language'] ?? 'ko',\n formFactor: formFactor as 'tablet' | 'phone' | 'pc' | undefined,\n deviceId: appInfoData?.['X-Channel-DeviceId'] ?? getCookie('deviceId'),\n appVersion: appInfoData?.['X-Channel-AppVersion'] ?? getCookie('appVersion'),\n loginType: appInfoData?.['X-Channel-LoginType'] ?? getCookie('loginType'),\n platformName: appInfoData?.['X-Channel-PlatformName'] ?? getCookie('platformName'),\n platformVersion: appInfoData?.['X-Channel-PlatformVersion'] ?? getCookie('platformVersion'),\n deviceModel: appInfoData?.['X-Channel-DeviceModel'] ?? getCookie('deviceModel'),\n loginChannel: loginChannel as 'DSP' | 'MSP',\n businessWorkDivisionCode: getBusinessWorkDivisionCode()\n };\n};\n\n/**\n * 로그인한 FP 사용자 정보 불러오기\n * @returns\n */\nexport const getFpUserInfo = async () => {\n try {\n const { isSuccess, data } = await getUserProfile();\n\n if (isSuccess && data) {\n console.log('[useSetupClientSession-getFpUserInfo] 프로필 로드 성공');\n\n return data;\n }\n\n console.warn('[useSetupClientSession-getFpUserInfo] 프로필 로드 실패: 응답 없음');\n\n return null;\n } catch (error) {\n console.error('[useSetupClientSession-getFpUserInfo] 프로필 로드 실패:', error);\n\n return null;\n }\n};\n","import { useEffect } from 'react';\n\nimport { useClientSession, useSetClientSession } from 'sales-frontend-stores';\nimport { isWebView } from 'sales-frontend-utils';\n\nimport { setEntryToSessionStorage } from '../navigation/history-back-handler';\n\nimport { createWebviewClientSession, createPureWebClientSession, getFpUserInfo } from './client-session-utils';\n/**\n * 앱 시작 시 ClientSession을 플랫폼(웹뷰, 순수 웹)에 맞게 자동 설정하는 훅\n *\n * @returns {boolean} 초기화 완료 여부\n */\nexport const useSetupClientSession = (): boolean => {\n const { isInitialized, isLoggedIn, userType } = useClientSession();\n const setClientSession = useSetClientSession();\n\n useEffect(() => {\n if (isInitialized) {\n console.log('[useSetupClientSession] Already initialized');\n\n return;\n }\n\n const initialize = async () => {\n try {\n console.log('[useSetupClientSession] 초기화 시작...');\n\n if (isWebView()) {\n console.log('[useSetupClientSession] 웹뷰 환경 감지');\n // 최초 진입 경로 저장\n setEntryToSessionStorage();\n\n setClientSession(await createWebviewClientSession());\n } else {\n console.log('[useSetupClientSession] 순수 웹 환경 감지');\n setClientSession(await createPureWebClientSession());\n }\n\n console.log('[useSetupClientSession] 기본 세션 설정 완료');\n } catch (error) {\n console.error('[useSetupClientSession] 초기화 실패:', error);\n }\n };\n\n // 기본 초기화\n initialize();\n }, [isInitialized, setClientSession]);\n\n useEffect(() => {\n if (!isInitialized || !isLoggedIn) {\n return;\n }\n\n // 로그인 FP 사용자 불러오기\n if (userType === 'FP') {\n const loadUserInfo = async () => {\n console.log('[useSetupClientSession] 사용자 프로필 로드 시작...');\n\n const userInfo = await getFpUserInfo();\n if (userInfo) {\n setClientSession(userInfo);\n }\n };\n\n loadUserInfo();\n }\n }, [isInitialized, isLoggedIn, userType, setClientSession]);\n\n // 초기화 완료 여부 반환\n return isInitialized ?? false;\n};\n","import { useSetupClientSession } from './use-setup-client-session';\n\ninterface ClientSessionProviderProps {\n children: React.ReactNode;\n /**\n * 초기화 중 표시할 로딩 컴포넌트\n */\n loadingComponent?: React.ReactNode;\n}\n\n/**\n * ClientSession 초기화를 담당하는 Provider 컴포넌트\n * 앱의 최상위에서 사용하여 플랫폼별 세션 정보를 자동으로 설정합니다.\n */\nexport const ClientSessionProvider = ({ children, loadingComponent = null }: ClientSessionProviderProps) => {\n const isInitialized = useSetupClientSession();\n\n // 초기화 완료 전까지 fallback 표시\n if (!isInitialized) {\n return <>{loadingComponent}</>;\n }\n\n return <>{children}</>;\n};\n"]}
|
package/dist/index.js
CHANGED
|
@@ -102,24 +102,24 @@ var createWebviewClientSession = async () => {
|
|
|
102
102
|
businessWorkDivisionCode: getBusinessWorkDivisionCode()
|
|
103
103
|
};
|
|
104
104
|
};
|
|
105
|
-
var
|
|
105
|
+
var getFpUserInfo = async () => {
|
|
106
106
|
try {
|
|
107
107
|
const { isSuccess, data } = await getUserProfile();
|
|
108
108
|
if (isSuccess && data) {
|
|
109
|
-
console.log("[useSetupClientSession] \uD504\uB85C\uD544 \uB85C\uB4DC \uC131\uACF5");
|
|
109
|
+
console.log("[useSetupClientSession-getFpUserInfo] \uD504\uB85C\uD544 \uB85C\uB4DC \uC131\uACF5");
|
|
110
110
|
return data;
|
|
111
111
|
}
|
|
112
|
-
console.warn("[
|
|
112
|
+
console.warn("[useSetupClientSession-getFpUserInfo] \uD504\uB85C\uD544 \uB85C\uB4DC \uC2E4\uD328: \uC751\uB2F5 \uC5C6\uC74C");
|
|
113
113
|
return null;
|
|
114
114
|
} catch (error) {
|
|
115
|
-
console.error("[
|
|
115
|
+
console.error("[useSetupClientSession-getFpUserInfo] \uD504\uB85C\uD544 \uB85C\uB4DC \uC2E4\uD328:", error);
|
|
116
116
|
return null;
|
|
117
117
|
}
|
|
118
118
|
};
|
|
119
119
|
|
|
120
120
|
// src/client-session/use-setup-client-session.tsx
|
|
121
121
|
var useSetupClientSession = () => {
|
|
122
|
-
const { isInitialized, isLoggedIn } = useClientSession();
|
|
122
|
+
const { isInitialized, isLoggedIn, userType } = useClientSession();
|
|
123
123
|
const setClientSession = useSetClientSession();
|
|
124
124
|
useEffect(() => {
|
|
125
125
|
if (isInitialized) {
|
|
@@ -148,15 +148,17 @@ var useSetupClientSession = () => {
|
|
|
148
148
|
if (!isInitialized || !isLoggedIn) {
|
|
149
149
|
return;
|
|
150
150
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
151
|
+
if (userType === "FP") {
|
|
152
|
+
const loadUserInfo = async () => {
|
|
153
|
+
console.log("[useSetupClientSession] \uC0AC\uC6A9\uC790 \uD504\uB85C\uD544 \uB85C\uB4DC \uC2DC\uC791...");
|
|
154
|
+
const userInfo = await getFpUserInfo();
|
|
155
|
+
if (userInfo) {
|
|
156
|
+
setClientSession(userInfo);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
loadUserInfo();
|
|
160
|
+
}
|
|
161
|
+
}, [isInitialized, isLoggedIn, userType, setClientSession]);
|
|
160
162
|
return isInitialized ?? false;
|
|
161
163
|
};
|
|
162
164
|
var ClientSessionProvider = ({ children, loadingComponent = null }) => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/navigation/history-back-handler.tsx","../src/client-session/client-session-utils.ts","../src/client-session/use-setup-client-session.tsx","../src/client-session/client-session-provider.tsx"],"names":["Bridge","isWebView"],"mappings":"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","file":"index.js","sourcesContent":["import { Bridge } from 'sales-frontend-bridge';\nimport { isWebView } from 'sales-frontend-utils';\n\nexport const ENTRY_PATH_KEY = 'ENTRY_PATH';\n\nexport interface NativeEntry {\n path: string;\n timestamp: number;\n}\n\n/**\n * 뒤로가기 핸들러\n * 네이티브 앱 기본: 뒤로가다가 첫 페이지일 경우 웹뷰 닫기\n */\nexport const handleHistoryBack = () => {\n // 순수 웹인 경우 일반 뒤로가기\n if (!isWebView()) {\n window.history.back();\n\n return;\n }\n\n const entryStr = sessionStorage.getItem(ENTRY_PATH_KEY);\n if (!entryStr) {\n window.history.back();\n\n return;\n }\n\n try {\n const entry: NativeEntry = JSON.parse(entryStr);\n const currentPath = window.location.pathname + window.location.search;\n const timeSinceEntry = Date.now() - entry.timestamp;\n\n // 진입 경로이고 + 진입 후 5초 이내\n if (currentPath === entry.path && timeSinceEntry >= 1) {\n console.log('[handleBack] 진입 페이지 - 웹뷰 닫기');\n Bridge.native.closeWeb();\n } else {\n console.log('[handleBack] 일반 뒤로가기');\n window.history.back();\n }\n } catch (error) {\n console.error('[handleBack] Entry 파싱 실패:', error);\n window.history.back();\n }\n};\n\nexport const setEntryToSessionStorage = () => {\n const entry: NativeEntry = {\n path: window.location.pathname + window.location.search,\n timestamp: Date.now()\n };\n sessionStorage.setItem(ENTRY_PATH_KEY, JSON.stringify(entry));\n};\n","import { getUserProfile } from 'sales-frontend-api/method';\nimport { Bridge } from 'sales-frontend-bridge';\nimport {\n getCookie,\n getOrCreateDeviceId,\n getBrowserName,\n getBrowserVersion,\n getOSName,\n getOSVersion,\n getDeviceModel,\n isSalesPortal,\n getFormFactorFromUserAgent,\n isFpPlannerApp,\n getBusinessWorkDivisionCode\n} from 'sales-frontend-utils';\n\nimport type { ClientSession } from 'sales-frontend-stores';\n\n/**\n * URL 경로의 두 번째 세그먼트에서 폼팩터를 추출하거나 User Agent로 감지\n * @param pathname - URL 경로 (예: /aaa/mobile, /aaa/tablet, /aaa/pc)\n * @returns 'mobile' | 'tablet' | 'pc'\n */\nconst getFormFactor = (): 'phone' | 'tablet' | 'pc' | undefined => {\n const { pathname } = location;\n\n // pathname이 제공된 경우 URL에서 추출 시도\n if (pathname) {\n const segments = pathname.split('/').filter(Boolean);\n\n // 두 번째 세그먼트 확인 (인덱스 1)\n if (segments.length >= 2) {\n const secondSegment = segments[1]?.toLowerCase();\n\n if (secondSegment === 'mobile') {\n return 'phone';\n }\n if (secondSegment === 'tablet') {\n return 'tablet';\n }\n if (secondSegment === 'pc') {\n return 'pc';\n }\n }\n }\n\n // URL에 없으면 User Agent로 감지\n return getFormFactorFromUserAgent(navigator.userAgent);\n};\n\n/**\n * 순수 웹 상태값 초기화\n * @returns\n */\nexport const createPureWebClientSession = async (): Promise<ClientSession> => {\n const hasAccessToken = !!getCookie('accessToken');\n\n return {\n isInitialized: true,\n isLoggedIn: hasAccessToken,\n isWebView: false,\n acceptLanguage: navigator.language || 'ko',\n formFactor: getFormFactor(),\n deviceId: getOrCreateDeviceId(),\n appVersion: `${getBrowserName(navigator.userAgent)} ${getBrowserVersion(navigator.userAgent)}`,\n loginType: 'web-login',\n platformName: getOSName(navigator.userAgent),\n platformVersion: getOSVersion(navigator.userAgent),\n deviceModel: getDeviceModel(),\n loginChannel: isSalesPortal() ? 'HMP' : 'WEB',\n businessWorkDivisionCode: getBusinessWorkDivisionCode()\n };\n};\n\n/**\n * 웹뷰 상태값 초기화\n * @returns\n */\nexport const createWebviewClientSession = async (): Promise<ClientSession> => {\n const [appInfo, accessToken] = await Promise.allSettled([\n Bridge.native.getAppInfo(),\n isFpPlannerApp()\n ? Promise.resolve(getCookie('accessToken'))\n : Bridge.native.getAccessToken().then((res) => res.accessToken)\n ]);\n\n const appInfoData = appInfo.status === 'fulfilled' ? appInfo.value : null;\n const isLoggedIn = accessToken.status === 'fulfilled' ? !!accessToken.value : false;\n\n const formFactor =\n appInfoData?.['X-Channel-FormFactor']?.toLowerCase() ?? getCookie('formFactor')?.toLowerCase() ?? getFormFactor();\n\n const loginChannel = appInfoData?.['X-Channel-LoginChannel'] ?? getCookie('loginChannel') ?? 'DSP';\n\n return {\n isInitialized: true,\n isLoggedIn,\n isWebView: true,\n acceptLanguage: appInfoData?.['Accept-Language'] ?? 'ko',\n formFactor: formFactor as 'tablet' | 'phone' | 'pc' | undefined,\n deviceId: appInfoData?.['X-Channel-DeviceId'] ?? getCookie('deviceId'),\n appVersion: appInfoData?.['X-Channel-AppVersion'] ?? getCookie('appVersion'),\n loginType: appInfoData?.['X-Channel-LoginType'] ?? getCookie('loginType'),\n platformName: appInfoData?.['X-Channel-PlatformName'] ?? getCookie('platformName'),\n platformVersion: appInfoData?.['X-Channel-PlatformVersion'] ?? getCookie('platformVersion'),\n deviceModel: appInfoData?.['X-Channel-DeviceModel'] ?? getCookie('deviceModel'),\n loginChannel: loginChannel as 'DSP' | 'MSP',\n businessWorkDivisionCode: getBusinessWorkDivisionCode()\n };\n};\n\nexport const getLoginUserInfo = async () => {\n try {\n const { isSuccess, data } = await getUserProfile();\n\n if (isSuccess && data) {\n console.log('[useSetupClientSession] 프로필 로드 성공');\n\n return data;\n }\n\n console.warn('[getLoginUserInfo] 프로필 로드 실패: 응답 없음');\n\n return null;\n } catch (error) {\n console.error('[getLoginUserInfo] 프로필 로드 실패:', error);\n\n return null;\n }\n};\n","import { useEffect } from 'react';\n\nimport { useClientSession, useSetClientSession } from 'sales-frontend-stores';\nimport { isWebView } from 'sales-frontend-utils';\n\nimport { setEntryToSessionStorage } from '../navigation/history-back-handler';\n\nimport { createWebviewClientSession, createPureWebClientSession, getLoginUserInfo } from './client-session-utils';\n/**\n * 앱 시작 시 ClientSession을 플랫폼(웹뷰, 순수 웹)에 맞게 자동 설정하는 훅\n *\n * @returns {boolean} 초기화 완료 여부\n */\nexport const useSetupClientSession = (): boolean => {\n const { isInitialized, isLoggedIn } = useClientSession();\n const setClientSession = useSetClientSession();\n\n useEffect(() => {\n if (isInitialized) {\n console.log('[useSetupClientSession] Already initialized');\n\n return;\n }\n\n const initialize = async () => {\n try {\n console.log('[useSetupClientSession] 초기화 시작...');\n\n if (isWebView()) {\n console.log('[useSetupClientSession] 웹뷰 환경 감지');\n // 최초 진입 경로 저장\n setEntryToSessionStorage();\n\n setClientSession(await createWebviewClientSession());\n } else {\n console.log('[useSetupClientSession] 순수 웹 환경 감지');\n setClientSession(await createPureWebClientSession());\n }\n\n console.log('[useSetupClientSession] 기본 세션 설정 완료');\n } catch (error) {\n console.error('[useSetupClientSession] 초기화 실패:', error);\n }\n };\n\n // 기본 초기화\n initialize();\n }, [isInitialized, setClientSession]);\n\n useEffect(() => {\n if (!isInitialized || !isLoggedIn) {\n return;\n }\n\n const loadUserInfo = async () => {\n console.log('[useSetupClientSession] 사용자 프로필 로드 시작...');\n\n const userInfo = await getLoginUserInfo();\n if (userInfo) {\n setClientSession(userInfo);\n }\n };\n\n // 로그인 FP 사용자 불러오기\n loadUserInfo();\n }, [isInitialized, isLoggedIn, setClientSession]);\n\n // 초기화 완료 여부 반환\n return isInitialized ?? false;\n};\n","import { useSetupClientSession } from './use-setup-client-session';\n\ninterface ClientSessionProviderProps {\n children: React.ReactNode;\n /**\n * 초기화 중 표시할 로딩 컴포넌트\n */\n loadingComponent?: React.ReactNode;\n}\n\n/**\n * ClientSession 초기화를 담당하는 Provider 컴포넌트\n * 앱의 최상위에서 사용하여 플랫폼별 세션 정보를 자동으로 설정합니다.\n */\nexport const ClientSessionProvider = ({ children, loadingComponent = null }: ClientSessionProviderProps) => {\n const isInitialized = useSetupClientSession();\n\n // 초기화 완료 전까지 fallback 표시\n if (!isInitialized) {\n return <>{loadingComponent}</>;\n }\n\n return <>{children}</>;\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/navigation/history-back-handler.tsx","../src/client-session/client-session-utils.ts","../src/client-session/use-setup-client-session.tsx","../src/client-session/client-session-provider.tsx"],"names":["Bridge","isWebView"],"mappings":"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","file":"index.js","sourcesContent":["import { Bridge } from 'sales-frontend-bridge';\nimport { isWebView } from 'sales-frontend-utils';\n\nexport const ENTRY_PATH_KEY = 'ENTRY_PATH';\n\nexport interface NativeEntry {\n path: string;\n timestamp: number;\n}\n\n/**\n * 뒤로가기 핸들러\n * 네이티브 앱 기본: 뒤로가다가 첫 페이지일 경우 웹뷰 닫기\n */\nexport const handleHistoryBack = () => {\n // 순수 웹인 경우 일반 뒤로가기\n if (!isWebView()) {\n window.history.back();\n\n return;\n }\n\n const entryStr = sessionStorage.getItem(ENTRY_PATH_KEY);\n if (!entryStr) {\n window.history.back();\n\n return;\n }\n\n try {\n const entry: NativeEntry = JSON.parse(entryStr);\n const currentPath = window.location.pathname + window.location.search;\n const timeSinceEntry = Date.now() - entry.timestamp;\n\n // 진입 경로이고 + 진입 후 5초 이내\n if (currentPath === entry.path && timeSinceEntry >= 1) {\n console.log('[handleBack] 진입 페이지 - 웹뷰 닫기');\n Bridge.native.closeWeb();\n } else {\n console.log('[handleBack] 일반 뒤로가기');\n window.history.back();\n }\n } catch (error) {\n console.error('[handleBack] Entry 파싱 실패:', error);\n window.history.back();\n }\n};\n\nexport const setEntryToSessionStorage = () => {\n const entry: NativeEntry = {\n path: window.location.pathname + window.location.search,\n timestamp: Date.now()\n };\n sessionStorage.setItem(ENTRY_PATH_KEY, JSON.stringify(entry));\n};\n","import { getUserProfile } from 'sales-frontend-api/method';\nimport { Bridge } from 'sales-frontend-bridge';\nimport {\n getCookie,\n getOrCreateDeviceId,\n getBrowserName,\n getBrowserVersion,\n getOSName,\n getOSVersion,\n getDeviceModel,\n isSalesPortal,\n getFormFactorFromUserAgent,\n isFpPlannerApp,\n getBusinessWorkDivisionCode\n} from 'sales-frontend-utils';\n\nimport type { ClientSession } from 'sales-frontend-stores';\n\n/**\n * URL 경로의 두 번째 세그먼트에서 폼팩터를 추출하거나 User Agent로 감지\n * @param pathname - URL 경로 (예: /aaa/mobile, /aaa/tablet, /aaa/pc)\n * @returns 'mobile' | 'tablet' | 'pc'\n */\nconst getFormFactor = (): 'phone' | 'tablet' | 'pc' | undefined => {\n const { pathname } = location;\n\n // pathname이 제공된 경우 URL에서 추출 시도\n if (pathname) {\n const segments = pathname.split('/').filter(Boolean);\n\n // 두 번째 세그먼트 확인 (인덱스 1)\n if (segments.length >= 2) {\n const secondSegment = segments[1]?.toLowerCase();\n\n if (secondSegment === 'mobile') {\n return 'phone';\n }\n if (secondSegment === 'tablet') {\n return 'tablet';\n }\n if (secondSegment === 'pc') {\n return 'pc';\n }\n }\n }\n\n // URL에 없으면 User Agent로 감지\n return getFormFactorFromUserAgent(navigator.userAgent);\n};\n\n/**\n * 순수 웹 상태값 초기화\n * @returns\n */\nexport const createPureWebClientSession = async (): Promise<ClientSession> => {\n const hasAccessToken = !!getCookie('accessToken');\n\n return {\n isInitialized: true,\n isLoggedIn: hasAccessToken,\n isWebView: false,\n acceptLanguage: navigator.language || 'ko',\n formFactor: getFormFactor(),\n deviceId: getOrCreateDeviceId(),\n appVersion: `${getBrowserName(navigator.userAgent)} ${getBrowserVersion(navigator.userAgent)}`,\n loginType: 'web-login',\n platformName: getOSName(navigator.userAgent),\n platformVersion: getOSVersion(navigator.userAgent),\n deviceModel: getDeviceModel(),\n loginChannel: isSalesPortal() ? 'HMP' : 'WEB',\n businessWorkDivisionCode: getBusinessWorkDivisionCode()\n };\n};\n\n/**\n * 웹뷰 상태값 초기화\n * @returns\n */\nexport const createWebviewClientSession = async (): Promise<ClientSession> => {\n const [appInfo, accessToken] = await Promise.allSettled([\n Bridge.native.getAppInfo(),\n isFpPlannerApp()\n ? Promise.resolve(getCookie('accessToken'))\n : Bridge.native.getAccessToken().then((res) => res.accessToken)\n ]);\n\n const appInfoData = appInfo.status === 'fulfilled' ? appInfo.value : null;\n const isLoggedIn = accessToken.status === 'fulfilled' ? !!accessToken.value : false;\n\n const formFactor =\n appInfoData?.['X-Channel-FormFactor']?.toLowerCase() ?? getCookie('formFactor')?.toLowerCase() ?? getFormFactor();\n\n const loginChannel = appInfoData?.['X-Channel-LoginChannel'] ?? getCookie('loginChannel') ?? 'DSP';\n\n return {\n isInitialized: true,\n isLoggedIn,\n isWebView: true,\n acceptLanguage: appInfoData?.['Accept-Language'] ?? 'ko',\n formFactor: formFactor as 'tablet' | 'phone' | 'pc' | undefined,\n deviceId: appInfoData?.['X-Channel-DeviceId'] ?? getCookie('deviceId'),\n appVersion: appInfoData?.['X-Channel-AppVersion'] ?? getCookie('appVersion'),\n loginType: appInfoData?.['X-Channel-LoginType'] ?? getCookie('loginType'),\n platformName: appInfoData?.['X-Channel-PlatformName'] ?? getCookie('platformName'),\n platformVersion: appInfoData?.['X-Channel-PlatformVersion'] ?? getCookie('platformVersion'),\n deviceModel: appInfoData?.['X-Channel-DeviceModel'] ?? getCookie('deviceModel'),\n loginChannel: loginChannel as 'DSP' | 'MSP',\n businessWorkDivisionCode: getBusinessWorkDivisionCode()\n };\n};\n\n/**\n * 로그인한 FP 사용자 정보 불러오기\n * @returns\n */\nexport const getFpUserInfo = async () => {\n try {\n const { isSuccess, data } = await getUserProfile();\n\n if (isSuccess && data) {\n console.log('[useSetupClientSession-getFpUserInfo] 프로필 로드 성공');\n\n return data;\n }\n\n console.warn('[useSetupClientSession-getFpUserInfo] 프로필 로드 실패: 응답 없음');\n\n return null;\n } catch (error) {\n console.error('[useSetupClientSession-getFpUserInfo] 프로필 로드 실패:', error);\n\n return null;\n }\n};\n","import { useEffect } from 'react';\n\nimport { useClientSession, useSetClientSession } from 'sales-frontend-stores';\nimport { isWebView } from 'sales-frontend-utils';\n\nimport { setEntryToSessionStorage } from '../navigation/history-back-handler';\n\nimport { createWebviewClientSession, createPureWebClientSession, getFpUserInfo } from './client-session-utils';\n/**\n * 앱 시작 시 ClientSession을 플랫폼(웹뷰, 순수 웹)에 맞게 자동 설정하는 훅\n *\n * @returns {boolean} 초기화 완료 여부\n */\nexport const useSetupClientSession = (): boolean => {\n const { isInitialized, isLoggedIn, userType } = useClientSession();\n const setClientSession = useSetClientSession();\n\n useEffect(() => {\n if (isInitialized) {\n console.log('[useSetupClientSession] Already initialized');\n\n return;\n }\n\n const initialize = async () => {\n try {\n console.log('[useSetupClientSession] 초기화 시작...');\n\n if (isWebView()) {\n console.log('[useSetupClientSession] 웹뷰 환경 감지');\n // 최초 진입 경로 저장\n setEntryToSessionStorage();\n\n setClientSession(await createWebviewClientSession());\n } else {\n console.log('[useSetupClientSession] 순수 웹 환경 감지');\n setClientSession(await createPureWebClientSession());\n }\n\n console.log('[useSetupClientSession] 기본 세션 설정 완료');\n } catch (error) {\n console.error('[useSetupClientSession] 초기화 실패:', error);\n }\n };\n\n // 기본 초기화\n initialize();\n }, [isInitialized, setClientSession]);\n\n useEffect(() => {\n if (!isInitialized || !isLoggedIn) {\n return;\n }\n\n // 로그인 FP 사용자 불러오기\n if (userType === 'FP') {\n const loadUserInfo = async () => {\n console.log('[useSetupClientSession] 사용자 프로필 로드 시작...');\n\n const userInfo = await getFpUserInfo();\n if (userInfo) {\n setClientSession(userInfo);\n }\n };\n\n loadUserInfo();\n }\n }, [isInitialized, isLoggedIn, userType, setClientSession]);\n\n // 초기화 완료 여부 반환\n return isInitialized ?? false;\n};\n","import { useSetupClientSession } from './use-setup-client-session';\n\ninterface ClientSessionProviderProps {\n children: React.ReactNode;\n /**\n * 초기화 중 표시할 로딩 컴포넌트\n */\n loadingComponent?: React.ReactNode;\n}\n\n/**\n * ClientSession 초기화를 담당하는 Provider 컴포넌트\n * 앱의 최상위에서 사용하여 플랫폼별 세션 정보를 자동으로 설정합니다.\n */\nexport const ClientSessionProvider = ({ children, loadingComponent = null }: ClientSessionProviderProps) => {\n const isInitialized = useSetupClientSession();\n\n // 초기화 완료 전까지 fallback 표시\n if (!isInitialized) {\n return <>{loadingComponent}</>;\n }\n\n return <>{children}</>;\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sales-frontend-features",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.25",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -27,18 +27,18 @@
|
|
|
27
27
|
"react": "^19.1.0",
|
|
28
28
|
"tsup": "^8.4.0",
|
|
29
29
|
"typescript": "5.8.2",
|
|
30
|
-
"sales-frontend-
|
|
30
|
+
"eslint-config-sales-frontend-eslint-config-v8": "^0.0.6",
|
|
31
31
|
"sales-frontend-typescript-config": "0.0.2",
|
|
32
|
-
"sales-frontend-
|
|
33
|
-
"sales-frontend-stores": "0.0.
|
|
34
|
-
"
|
|
32
|
+
"sales-frontend-api": "0.0.93",
|
|
33
|
+
"sales-frontend-stores": "0.0.7",
|
|
34
|
+
"sales-frontend-bridge": "0.0.63"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"react": ">=18.0.0",
|
|
38
38
|
"react-dom": ">=18.0.0",
|
|
39
|
-
"sales-frontend-
|
|
40
|
-
"sales-frontend-
|
|
41
|
-
"sales-frontend-
|
|
39
|
+
"sales-frontend-api": "0.0.93",
|
|
40
|
+
"sales-frontend-bridge": "0.0.63",
|
|
41
|
+
"sales-frontend-stores": "0.0.7"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"sales-frontend-utils": "0.0.25"
|