import * as amplitude from '@amplitude/analytics-browser' import type { PageDataResourceGroup } from '#layers/types/api/pageData' import type { AnalyticsDetailType } from '#layers/types/AnalyticsType' import type { IdentityInfo, ActionInfo, MarketingInfo, } from '#layers/types/Stove' declare const svcLog: any declare const twq: any declare const ttq: any /** * 페이지 데이터와 템플릿 정보를 기반으로 분석용 로그 데이터를 생성하는 composable (직접 객체 반환) * @param resourcesData 페이지 리소스 데이터 * @param pageVerTmplSeq 템플릿 시퀀스 번호 * @returns 분석용 로그 데이터 객체 (ref 없이) */ export const useAnalyticsLogDataDirect = ( resourcesData: PageDataResourceGroup | string, pageVerTmplSeq: number | null ) => { const store = usePageDataStore() const pageData = store.pageData if (!pageData) { return {} as AnalyticsDetailType } // resourcesData가 문자열인 경우 (예: 'view') if (typeof resourcesData === 'string') { const logData = { actionType: resourcesData, event: pageData.page_name, eventCategory: pageData.page_name, } as unknown as AnalyticsDetailType if (resourcesData === 'view') { logData.viewArea = pageData.page_name_en logData.viewType = 'pageView' } return logData } // resourcesData가 객체인 경우 (기존 로직) const pageDataTrack = resourcesData.tracking const logData = { actionType: pageDataTrack?.action_type, event: pageData.page_name, eventCategory: `${pageData.page_name}_${pageDataTrack?.click_sarea}_${pageDataTrack?.click_item}`, } as unknown as AnalyticsDetailType if (pageDataTrack.action_type === 'click') { logData.clickArea = pageData.page_name_en logData.clickSarea = pageDataTrack.click_sarea logData.clickItem = pageDataTrack.click_item } else if (pageDataTrack.action_type === 'view') { logData.viewArea = pageData.page_name_en logData.viewType = 'view_frame' } return logData } // target에 {XX1, XX2}와 같은 형태가 포함되어 있을 경우 options.clickItem으로부터 값 추출하여 세팅 const findValueFromOption = (target: string, { options = {} }: any) => { if (target.includes('{') && target.includes('}')) { const strTargetClickItem = target.substring( target.indexOf('{') + 1, target.indexOf('}') ) const arrTargetClickItem = strTargetClickItem.split(',') const arrTargetClickItemValue = [] for (let targetClickItem of arrTargetClickItem) { targetClickItem = targetClickItem.trim() arrTargetClickItemValue.push(options.clickItem[targetClickItem]) } target = target.replaceAll( `{${strTargetClickItem}}`, arrTargetClickItemValue.join(',') ) } return target } /** * Google Analytics 전송 * * @param {AnalyticsDetailType} analytics * @param {object} options */ const sendGA = (analytics: AnalyticsDetailType, { options = {} }: any) => { try { const { gtag } = useGtag() const eventName = analytics.event || '' const eventLocale = analytics.eventLocale || '' const eventCategory = `${analytics.eventCategory}` // GA 클릭 이벤트 명 뒤에 언어 값 추가 노출되도록 개발. ex) GNB_자유게시판_KO const eventLabel = `${eventCategory}_${eventLocale}` gtag('set', 'cookie_domain', `${window?.location?.hostname || ''}`) // env 값으로 설정 시 쿠키 생성 안 돼서 window.location.hostname으로 설정 gtag('set', 'cookie_expires', '0') // 0으로 설정 시 쿠키가 Session 기반 쿠키로 전환 gtag('event', `${eventName}`, { event_category: eventLabel, }) } catch (e) { console.error('[Exception] useAnalytics.sendGA: ', e) } } /** * Stove Analytics(81 Plug) 전송 * * @param {AnalyticsDetailType} analytics * @param {string} mcode * @param {object} options */ const sendSA = ( analytics: AnalyticsDetailType, { mcode = '', options = {} }: any ) => { const gameDataStore = useGameDataStore() const { gameData } = storeToRefs(gameDataStore) try { const gameNo = gameData.value.game_code const device = useDevice() const deviceType = device.isDesktop ? 'pcweb' : 'mobileweb' const country = `${csrGetCountry()}` const memberNo = `${csrGetStoveMemberNo()}` const actionType = analytics.actionType || '' const logSourceType = analytics.logSourceType || '' const viewArea = analytics.viewArea || '' const viewType = analytics.viewType || '' const clickArea = analytics.clickArea || '' const clickSarea = findValueFromOption(analytics.clickSarea || '', { options, }) const eventLocale = analytics.eventLocale || '' const identityInfo: IdentityInfo = { app_id: 'stove', log_source_type: logSourceType, country, locale: eventLocale, lang_cd: eventLocale, member_no: memberNo, channeling_cd: 'SO', } const marketingInfo: MarketingInfo = { marketing_code: mcode || '', device_type: deviceType, media_type: '', media_page: '', } let actionParam = {} if (actionType === 'view') { actionParam = { view_area: viewArea, view_type: viewType, view_info: { game_no: gameNo, lang_cd: eventLocale, ...options?.viewInfo, }, } } else if (actionType === 'click') { actionParam = { click_area: clickArea, click_sarea: clickSarea, click_item: { click_item: analytics.clickItem, game_no: gameNo, lang_cd: eventLocale, ...options?.clickItem, }, } } const actionInfo: ActionInfo = { action_type: actionType, action_param: actionParam, marketing_info: marketingInfo, } const amplitudeActionInfo = { ...actionInfo, url: `${location?.href || ''}`, agent: `${navigator?.userAgent || ''}`, } const amplitudeActionParams: { event_type: string event_properties: ActionInfo & { url: string; agent: string } } = { event_type: actionType, event_properties: amplitudeActionInfo, } svcLog.identity(identityInfo) svcLog.action(actionInfo, {}, {}) // 81plug warning log 제거를 위해 2번째 인자부터 빈 객체 세팅 amplitude.track(amplitudeActionParams) } catch (e) { console.error('[Exception] useAnalytics.sendSA: ', e) } } /** * 기본 로그 일괄 전송 * * @param {string} locale * @param {AnalyticsDetailType} analytics */ const sendLog = (locale: string, analytics: AnalyticsDetailType) => { // 언어 코드 대문자 변환 analytics.eventLocale = locale.toUpperCase() if (analytics) { // GA 전송 : eventCategory 유무로 판별 sendGA(analytics, { options: analytics.options }) // SA 전송 : actionType, logSourceType 유무로 판별 if ( analytics.actionType && analytics.actionType !== '' // analytics.logSourceType && // analytics.logSourceType !== '' ) { sendSA(analytics, { mcode: analytics.mcode, options: analytics.options }) } } } /** * Google Analytics 전송 (기본 이벤트만 전송) * * @param {string} gaEventName */ const sendGAEventOnly = (gaEventName: string) => { try { const { gtag } = useGtag() gtag('set', 'cookie_domain', `${window?.location?.hostname || ''}`) // env 값으로 설정 시 쿠키 생성 안 돼서 window.location.hostname으로 설정 gtag('set', 'cookie_expires', '0') // 0으로 설정 시 쿠키가 Session 기반 쿠키로 전환 gtag('event', `${gaEventName}`) } catch (e) { console.error('[Exception] useAnalytics.sendGAEventOnly: ', e) } } /** * 메타 픽셀 전송 * * @param {string} fbEventName * @description 수집 대상 페이지에 useHead({ meta: [loadMetaPixelMeta()] }) 선언 */ const sendMetaPixel = (fbEventName: string) => { try { const { $fbq } = useNuxtApp() if (typeof $fbq === 'function') { $fbq('trackCustom', fbEventName) } } catch (e) { console.error('[Exception] useAnalytics.sendMetaPixel: ', e) } } /** * X(트위터) 픽셀 전송 * * @param {string} twEventName * @description 수집 대상 페이지에 useHead({ script: [loadTwitterPixelScript()] }) 선언 */ const sendTwitterPixel = (twEventName: string) => { try { twq('event', twEventName, {}) } catch (e) { console.error('[Exception] useAnalytics.sendTwitterPixel: ', e) } } /** * 틱톡 픽셀 전송 * * @param {string} ttEventName * @description 수집 대상 페이지에 onMounted(() => { loadTikTokPixelScript() }) 선언 */ const sendTiktokPixel = (ttEventName: string) => { try { ttq.track(ttEventName) } catch (e) { console.error('[Exception] useAnalytics.sendTiktokPixel: ', e) } } /** * 마케팅 인텔리전스 팀 요청 마케팅 스크립트 일괄 전송 * * @param {string} gaEventName * @param {string} fbEventName * @param {string} twEventName * @param {string} ttEventName */ const sendMarketingScript = ({ gaEventName, fbEventName, twEventName, ttEventName, }: { gaEventName?: string fbEventName?: string twEventName?: string ttEventName?: string }) => { if (gaEventName) { sendGAEventOnly(gaEventName) } if (fbEventName) { sendMetaPixel(fbEventName) } if (twEventName) { sendTwitterPixel(twEventName) } if (ttEventName) { sendTiktokPixel(ttEventName) } } export default () => { return { sendGA, sendSA, sendLog, sendMarketingScript, useAnalyticsLogDataDirect, } }