Files
web-temp/layers/composables/useAnalytics.ts

366 lines
9.8 KiB
TypeScript

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가 객체인 경우 (기존 로직)
if (!resourcesData || !resourcesData.tracking) {
return {} as AnalyticsDetailType
}
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) => {
if (!import.meta.client) return
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
) => {
if (!import.meta.client) return
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: import.meta.client ? `${location?.href || ''}` : '',
agent: import.meta.client ? `${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) => {
if (!import.meta.client) return
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) => {
if (!import.meta.client) return
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) => {
if (!import.meta.client) return
try {
twq('event', twEventName, {})
} catch (e) {
console.error('[Exception] useAnalytics.sendTwitterPixel: ', e)
}
}
/**
* 틱톡 픽셀 전송
*
* @param {string} ttEventName
* @description 수집 대상 페이지에 onMounted(() => { loadTikTokPixelScript() }) 선언
*/
const sendTiktokPixel = (ttEventName: string) => {
if (!import.meta.client) return
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,
}
}