@adstage/web-sdk 1.3.3 → 1.4.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.
- package/README.md +178 -35
- package/dist/index.cjs.js +810 -481
- package/dist/index.d.ts +286 -97
- package/dist/index.esm.js +794 -457
- package/dist/index.standalone.js +794 -457
- package/package.json +2 -2
- package/src/constants/endpoints.ts +93 -0
- package/src/core/AdStage.ts +128 -0
- package/src/index.ts +14 -413
- package/src/managers/{slider-manager.ts → carousel-slider-manager.ts} +9 -8
- package/src/managers/event-tracker.ts +2 -4
- package/src/managers/{fade-slider-manager.ts → text-transition-manager.ts} +7 -7
- package/src/modules/ads/AdsModule.ts +525 -0
- package/src/modules/config/ConfigModule.ts +124 -0
- package/src/modules/deeplinks/DeeplinksModule.ts +0 -0
- package/src/modules/events/EventsModule.ts +106 -0
- package/src/types/config.ts +74 -3
- package/src/types/index.ts +2 -1
- package/src/utils/api-headers.ts +52 -0
- package/src/utils/dom-utils.ts +93 -0
- package/examples/README.md +0 -33
- package/examples/banner-ads.html +0 -512
- package/examples/index.html +0 -338
- package/examples/native-ads.html +0 -634
- package/examples/react-app/README.md +0 -70
- package/examples/react-app/index.html +0 -13
- package/examples/react-app/package-lock.json +0 -3042
- package/examples/react-app/package.json +0 -26
- package/examples/react-app/pnpm-lock.yaml +0 -1857
- package/examples/react-app/public/index.standalone.js +0 -2331
- package/examples/react-app/src/App.tsx +0 -226
- package/examples/react-app/src/index.css +0 -37
- package/examples/react-app/src/main.tsx +0 -10
- package/examples/react-app/tsconfig.json +0 -25
- package/examples/react-app/tsconfig.node.json +0 -10
- package/examples/react-app/vite.config.ts +0 -15
- package/examples/react-nextjs/app/globals.css +0 -200
- package/examples/react-nextjs/app/layout.tsx +0 -27
- package/examples/react-nextjs/app/page.tsx +0 -258
- package/examples/react-nextjs/next.config.js +0 -9
- package/examples/react-nextjs/package.json +0 -22
- package/examples/react-nextjs/pnpm-lock.yaml +0 -343
- package/examples/react-nextjs/tsconfig.json +0 -34
- package/examples/text-ads.html +0 -597
- package/examples/video-ads.html +0 -739
- package/src/react/components/AdErrorBoundary.tsx +0 -75
- package/src/react/components/AdSlot.tsx +0 -144
- package/src/react/components/BannerAd.tsx +0 -24
- package/src/react/components/InterstitialAd.tsx +0 -24
- package/src/react/components/NativeAd.tsx +0 -24
- package/src/react/components/TextAd.tsx +0 -24
- package/src/react/components/VideoAd.tsx +0 -24
- package/src/react/components/index.ts +0 -8
- package/src/react/hooks/index.ts +0 -4
- package/src/react/hooks/useAdSlot.ts +0 -83
- package/src/react/hooks/useAdStage.ts +0 -14
- package/src/react/hooks/useAdTracking.ts +0 -61
- package/src/react/index.ts +0 -4
- package/src/react/providers/AdStageProvider.tsx +0 -86
- package/src/react/providers/index.ts +0 -2
- package/src/utils/sdk-standalone.ts +0 -155
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import React, { Component, ErrorInfo, ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
interface AdErrorBoundaryProps {
|
|
4
|
-
children: ReactNode;
|
|
5
|
-
fallback?: ReactNode;
|
|
6
|
-
onError?: (error: Error, errorInfo: ErrorInfo) => void;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface AdErrorBoundaryState {
|
|
10
|
-
hasError: boolean;
|
|
11
|
-
error: Error | null;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 광고 컴포넌트에서 발생하는 오류를 포착하는 Error Boundary
|
|
16
|
-
* 광고 로딩 실패 시 fallback UI를 표시하고 앱 전체가 크래시되는 것을 방지
|
|
17
|
-
*/
|
|
18
|
-
export class AdErrorBoundary extends Component<AdErrorBoundaryProps, AdErrorBoundaryState> {
|
|
19
|
-
constructor(props: AdErrorBoundaryProps) {
|
|
20
|
-
super(props);
|
|
21
|
-
this.state = { hasError: false, error: null };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
static getDerivedStateFromError(error: Error): AdErrorBoundaryState {
|
|
25
|
-
return { hasError: true, error };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
|
29
|
-
console.error('AdStage Error Boundary caught an error:', error, errorInfo);
|
|
30
|
-
|
|
31
|
-
// 사용자 정의 에러 핸들러 호출
|
|
32
|
-
if (this.props.onError) {
|
|
33
|
-
this.props.onError(error, errorInfo);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
render() {
|
|
38
|
-
if (this.state.hasError) {
|
|
39
|
-
// 사용자 정의 fallback이 있으면 사용, 없으면 기본 fallback 표시
|
|
40
|
-
if (this.props.fallback) {
|
|
41
|
-
return this.props.fallback;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return (
|
|
45
|
-
<div
|
|
46
|
-
style={{
|
|
47
|
-
padding: '20px',
|
|
48
|
-
textAlign: 'center',
|
|
49
|
-
backgroundColor: '#fee',
|
|
50
|
-
border: '1px solid #fcc',
|
|
51
|
-
borderRadius: '4px',
|
|
52
|
-
color: '#c00',
|
|
53
|
-
}}
|
|
54
|
-
>
|
|
55
|
-
<h3>광고 로딩 오류</h3>
|
|
56
|
-
<p>광고를 불러오는 중 문제가 발생했습니다.</p>
|
|
57
|
-
<button
|
|
58
|
-
onClick={() => this.setState({ hasError: false, error: null })}
|
|
59
|
-
style={{
|
|
60
|
-
padding: '8px 16px',
|
|
61
|
-
backgroundColor: '#fff',
|
|
62
|
-
border: '1px solid #ccc',
|
|
63
|
-
borderRadius: '4px',
|
|
64
|
-
cursor: 'pointer',
|
|
65
|
-
}}
|
|
66
|
-
>
|
|
67
|
-
다시 시도
|
|
68
|
-
</button>
|
|
69
|
-
</div>
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return this.props.children;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useMemo } from 'react';
|
|
2
|
-
import { AdType } from '../../types/advertisement';
|
|
3
|
-
import { useAdStage } from '../hooks/useAdStage';
|
|
4
|
-
|
|
5
|
-
interface AdSlotProps {
|
|
6
|
-
slotId: string;
|
|
7
|
-
adType: AdType;
|
|
8
|
-
width?: string | number;
|
|
9
|
-
height?: string | number;
|
|
10
|
-
className?: string;
|
|
11
|
-
style?: React.CSSProperties;
|
|
12
|
-
autoSlideInterval?: number;
|
|
13
|
-
sliderEffect?: 'slide' | 'fade';
|
|
14
|
-
language?: string;
|
|
15
|
-
deviceType?: string;
|
|
16
|
-
country?: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* 범용 광고 슬롯 컴포넌트
|
|
21
|
-
* 모든 광고 타입을 지원하며 SSR 환경에서도 안전하게 동작
|
|
22
|
-
*/
|
|
23
|
-
export const AdSlot: React.FC<AdSlotProps> = ({
|
|
24
|
-
slotId,
|
|
25
|
-
adType,
|
|
26
|
-
width,
|
|
27
|
-
height,
|
|
28
|
-
className,
|
|
29
|
-
style,
|
|
30
|
-
autoSlideInterval = 3,
|
|
31
|
-
sliderEffect = 'slide',
|
|
32
|
-
language,
|
|
33
|
-
deviceType,
|
|
34
|
-
country,
|
|
35
|
-
}) => {
|
|
36
|
-
const containerRef = useRef<HTMLDivElement>(null);
|
|
37
|
-
const { sdk, isLoading, error } = useAdStage();
|
|
38
|
-
|
|
39
|
-
const containerId = useMemo(() => `adstage-${slotId}`, [slotId]);
|
|
40
|
-
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
if (!sdk || !containerRef.current || isLoading || error) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// 컨테이너에 ID 설정
|
|
47
|
-
containerRef.current.id = containerId;
|
|
48
|
-
|
|
49
|
-
// 광고 슬롯 생성
|
|
50
|
-
const createSlot = async () => {
|
|
51
|
-
try {
|
|
52
|
-
await sdk.createSlot(slotId, containerId, adType, {
|
|
53
|
-
width,
|
|
54
|
-
height,
|
|
55
|
-
language,
|
|
56
|
-
deviceType,
|
|
57
|
-
country,
|
|
58
|
-
autoSlideInterval,
|
|
59
|
-
sliderEffect,
|
|
60
|
-
});
|
|
61
|
-
} catch (err) {
|
|
62
|
-
console.error(`Failed to create ad slot ${slotId}:`, err);
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
createSlot();
|
|
67
|
-
|
|
68
|
-
// 클린업 함수
|
|
69
|
-
return () => {
|
|
70
|
-
// SDK에 removeSlot 메서드가 없으므로 DOM 정리만 수행
|
|
71
|
-
if (containerRef.current) {
|
|
72
|
-
containerRef.current.innerHTML = '';
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
}, [
|
|
76
|
-
sdk,
|
|
77
|
-
slotId,
|
|
78
|
-
containerId,
|
|
79
|
-
adType,
|
|
80
|
-
width,
|
|
81
|
-
height,
|
|
82
|
-
language,
|
|
83
|
-
deviceType,
|
|
84
|
-
country,
|
|
85
|
-
autoSlideInterval,
|
|
86
|
-
sliderEffect,
|
|
87
|
-
isLoading,
|
|
88
|
-
error,
|
|
89
|
-
]);
|
|
90
|
-
|
|
91
|
-
const containerStyle: React.CSSProperties = {
|
|
92
|
-
width: typeof width === 'number' ? `${width}px` : width,
|
|
93
|
-
height: typeof height === 'number' ? `${height}px` : height,
|
|
94
|
-
...style,
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// 로딩 상태 표시
|
|
98
|
-
if (isLoading) {
|
|
99
|
-
return (
|
|
100
|
-
<div
|
|
101
|
-
className={className}
|
|
102
|
-
style={{
|
|
103
|
-
...containerStyle,
|
|
104
|
-
display: 'flex',
|
|
105
|
-
alignItems: 'center',
|
|
106
|
-
justifyContent: 'center',
|
|
107
|
-
backgroundColor: '#f5f5f5',
|
|
108
|
-
border: '1px dashed #ccc',
|
|
109
|
-
color: '#999',
|
|
110
|
-
}}
|
|
111
|
-
>
|
|
112
|
-
Loading Ad...
|
|
113
|
-
</div>
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// 에러 상태 표시
|
|
118
|
-
if (error) {
|
|
119
|
-
return (
|
|
120
|
-
<div
|
|
121
|
-
className={className}
|
|
122
|
-
style={{
|
|
123
|
-
...containerStyle,
|
|
124
|
-
display: 'flex',
|
|
125
|
-
alignItems: 'center',
|
|
126
|
-
justifyContent: 'center',
|
|
127
|
-
backgroundColor: '#fee',
|
|
128
|
-
border: '1px solid #fcc',
|
|
129
|
-
color: '#c00',
|
|
130
|
-
}}
|
|
131
|
-
>
|
|
132
|
-
Ad Load Error
|
|
133
|
-
</div>
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return (
|
|
138
|
-
<div
|
|
139
|
-
ref={containerRef}
|
|
140
|
-
className={className}
|
|
141
|
-
style={containerStyle}
|
|
142
|
-
/>
|
|
143
|
-
);
|
|
144
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { AdType } from '../../types/advertisement';
|
|
3
|
-
import { AdSlot } from './AdSlot';
|
|
4
|
-
|
|
5
|
-
interface BannerAdProps {
|
|
6
|
-
slotId: string;
|
|
7
|
-
width?: string | number;
|
|
8
|
-
height?: string | number;
|
|
9
|
-
className?: string;
|
|
10
|
-
style?: React.CSSProperties;
|
|
11
|
-
autoSlideInterval?: number;
|
|
12
|
-
sliderEffect?: 'slide' | 'fade';
|
|
13
|
-
language?: string;
|
|
14
|
-
deviceType?: string;
|
|
15
|
-
country?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 배너 광고 전용 컴포넌트
|
|
20
|
-
* AdSlot의 래퍼로 adType이 BANNER로 고정됨
|
|
21
|
-
*/
|
|
22
|
-
export const BannerAd: React.FC<BannerAdProps> = (props) => {
|
|
23
|
-
return <AdSlot {...props} adType={AdType.BANNER} />;
|
|
24
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { AdType } from '../../types/advertisement';
|
|
3
|
-
import { AdSlot } from './AdSlot';
|
|
4
|
-
|
|
5
|
-
interface InterstitialAdProps {
|
|
6
|
-
slotId: string;
|
|
7
|
-
width?: string | number;
|
|
8
|
-
height?: string | number;
|
|
9
|
-
className?: string;
|
|
10
|
-
style?: React.CSSProperties;
|
|
11
|
-
autoSlideInterval?: number;
|
|
12
|
-
sliderEffect?: 'slide' | 'fade';
|
|
13
|
-
language?: string;
|
|
14
|
-
deviceType?: string;
|
|
15
|
-
country?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 인터스티셜 광고 전용 컴포넌트
|
|
20
|
-
* AdSlot의 래퍼로 adType이 INTERSTITIAL로 고정됨
|
|
21
|
-
*/
|
|
22
|
-
export const InterstitialAd: React.FC<InterstitialAdProps> = (props) => {
|
|
23
|
-
return <AdSlot {...props} adType={AdType.INTERSTITIAL} />;
|
|
24
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { AdType } from '../../types/advertisement';
|
|
3
|
-
import { AdSlot } from './AdSlot';
|
|
4
|
-
|
|
5
|
-
interface NativeAdProps {
|
|
6
|
-
slotId: string;
|
|
7
|
-
width?: string | number;
|
|
8
|
-
height?: string | number;
|
|
9
|
-
className?: string;
|
|
10
|
-
style?: React.CSSProperties;
|
|
11
|
-
autoSlideInterval?: number;
|
|
12
|
-
sliderEffect?: 'slide' | 'fade';
|
|
13
|
-
language?: string;
|
|
14
|
-
deviceType?: string;
|
|
15
|
-
country?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 네이티브 광고 전용 컴포넌트
|
|
20
|
-
* AdSlot의 래퍼로 adType이 NATIVE로 고정됨
|
|
21
|
-
*/
|
|
22
|
-
export const NativeAd: React.FC<NativeAdProps> = (props) => {
|
|
23
|
-
return <AdSlot {...props} adType={AdType.NATIVE} />;
|
|
24
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { AdType } from '../../types/advertisement';
|
|
3
|
-
import { AdSlot } from './AdSlot';
|
|
4
|
-
|
|
5
|
-
interface TextAdProps {
|
|
6
|
-
slotId: string;
|
|
7
|
-
width?: string | number;
|
|
8
|
-
height?: string | number;
|
|
9
|
-
className?: string;
|
|
10
|
-
style?: React.CSSProperties;
|
|
11
|
-
autoSlideInterval?: number;
|
|
12
|
-
sliderEffect?: 'slide' | 'fade';
|
|
13
|
-
language?: string;
|
|
14
|
-
deviceType?: string;
|
|
15
|
-
country?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 텍스트 광고 전용 컴포넌트
|
|
20
|
-
* AdSlot의 래퍼로 adType이 TEXT로 고정됨
|
|
21
|
-
*/
|
|
22
|
-
export const TextAd: React.FC<TextAdProps> = (props) => {
|
|
23
|
-
return <AdSlot {...props} adType={AdType.TEXT} />;
|
|
24
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { AdType } from '../../types/advertisement';
|
|
3
|
-
import { AdSlot } from './AdSlot';
|
|
4
|
-
|
|
5
|
-
interface VideoAdProps {
|
|
6
|
-
slotId: string;
|
|
7
|
-
width?: string | number;
|
|
8
|
-
height?: string | number;
|
|
9
|
-
className?: string;
|
|
10
|
-
style?: React.CSSProperties;
|
|
11
|
-
autoSlideInterval?: number;
|
|
12
|
-
sliderEffect?: 'slide' | 'fade';
|
|
13
|
-
language?: string;
|
|
14
|
-
deviceType?: string;
|
|
15
|
-
country?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 비디오 광고 전용 컴포넌트
|
|
20
|
-
* AdSlot의 래퍼로 adType이 VIDEO로 고정됨
|
|
21
|
-
*/
|
|
22
|
-
export const VideoAd: React.FC<VideoAdProps> = (props) => {
|
|
23
|
-
return <AdSlot {...props} adType={AdType.VIDEO} />;
|
|
24
|
-
};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// React 컴포넌트들
|
|
2
|
-
export { AdSlot } from './AdSlot';
|
|
3
|
-
export { BannerAd } from './BannerAd';
|
|
4
|
-
export { TextAd } from './TextAd';
|
|
5
|
-
export { NativeAd } from './NativeAd';
|
|
6
|
-
export { VideoAd } from './VideoAd';
|
|
7
|
-
export { InterstitialAd } from './InterstitialAd';
|
|
8
|
-
export { AdErrorBoundary } from './AdErrorBoundary';
|
package/src/react/hooks/index.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
import { AdType } from '../../types/advertisement';
|
|
3
|
-
import { useAdStage } from './useAdStage';
|
|
4
|
-
|
|
5
|
-
interface UseAdSlotOptions {
|
|
6
|
-
slotId: string;
|
|
7
|
-
containerId: string;
|
|
8
|
-
adType: AdType;
|
|
9
|
-
width?: string | number;
|
|
10
|
-
height?: string | number;
|
|
11
|
-
language?: string;
|
|
12
|
-
deviceType?: string;
|
|
13
|
-
country?: string;
|
|
14
|
-
autoSlideInterval?: number;
|
|
15
|
-
sliderEffect?: 'slide' | 'fade';
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface UseAdSlotReturn {
|
|
19
|
-
isLoading: boolean;
|
|
20
|
-
error: string | null;
|
|
21
|
-
isCreated: boolean;
|
|
22
|
-
createSlot: () => Promise<void>;
|
|
23
|
-
resetSlot: () => void;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* 광고 슬롯 생성 및 관리를 위한 Hook
|
|
28
|
-
* 컴포넌트에서 직접 슬롯을 제어하고 싶을 때 사용
|
|
29
|
-
*/
|
|
30
|
-
export const useAdSlot = (options: UseAdSlotOptions): UseAdSlotReturn => {
|
|
31
|
-
const { sdk } = useAdStage();
|
|
32
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
33
|
-
const [error, setError] = useState<string | null>(null);
|
|
34
|
-
const [isCreated, setIsCreated] = useState(false);
|
|
35
|
-
|
|
36
|
-
const createSlot = async () => {
|
|
37
|
-
if (!sdk) {
|
|
38
|
-
setError('SDK not initialized');
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
setIsLoading(true);
|
|
43
|
-
setError(null);
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
await sdk.createSlot(options.slotId, options.containerId, options.adType, {
|
|
47
|
-
width: options.width,
|
|
48
|
-
height: options.height,
|
|
49
|
-
language: options.language,
|
|
50
|
-
deviceType: options.deviceType,
|
|
51
|
-
country: options.country,
|
|
52
|
-
autoSlideInterval: options.autoSlideInterval,
|
|
53
|
-
sliderEffect: options.sliderEffect,
|
|
54
|
-
});
|
|
55
|
-
setIsCreated(true);
|
|
56
|
-
} catch (err) {
|
|
57
|
-
const errorMessage = err instanceof Error ? err.message : '슬롯 생성 중 오류가 발생했습니다.';
|
|
58
|
-
setError(errorMessage);
|
|
59
|
-
setIsCreated(false);
|
|
60
|
-
} finally {
|
|
61
|
-
setIsLoading(false);
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const resetSlot = () => {
|
|
66
|
-
setIsLoading(false);
|
|
67
|
-
setError(null);
|
|
68
|
-
setIsCreated(false);
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// SDK가 변경되면 상태 초기화
|
|
72
|
-
useEffect(() => {
|
|
73
|
-
resetSlot();
|
|
74
|
-
}, [sdk]);
|
|
75
|
-
|
|
76
|
-
return {
|
|
77
|
-
isLoading,
|
|
78
|
-
error,
|
|
79
|
-
isCreated,
|
|
80
|
-
createSlot,
|
|
81
|
-
resetSlot,
|
|
82
|
-
};
|
|
83
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { useContext } from 'react';
|
|
2
|
-
import { AdStageContext, type AdStageContextValue } from '../providers/AdStageProvider';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* AdStage SDK 인스턴스에 접근하기 위한 Hook
|
|
6
|
-
* AdStageProvider 내부에서만 사용 가능
|
|
7
|
-
*/
|
|
8
|
-
export const useAdStage = (): AdStageContextValue => {
|
|
9
|
-
const context = useContext(AdStageContext);
|
|
10
|
-
if (!context) {
|
|
11
|
-
throw new Error('useAdStage must be used within an AdStageProvider');
|
|
12
|
-
}
|
|
13
|
-
return context;
|
|
14
|
-
};
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
|
-
import { AdEventType } from '../../types/advertisement';
|
|
3
|
-
import { useAdStage } from './useAdStage';
|
|
4
|
-
|
|
5
|
-
interface UseAdTrackingReturn {
|
|
6
|
-
trackEvent: (adId: string, slotId: string, eventType: AdEventType) => void;
|
|
7
|
-
trackClick: (adId: string, slotId: string) => void;
|
|
8
|
-
trackImpression: (adId: string, slotId: string) => void;
|
|
9
|
-
trackView: (adId: string, slotId: string) => void;
|
|
10
|
-
trackClose: (adId: string, slotId: string) => void;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* 광고 이벤트 추적을 위한 Hook
|
|
15
|
-
* 커스텀 이벤트 추적이 필요할 때 사용
|
|
16
|
-
*/
|
|
17
|
-
export const useAdTracking = (): UseAdTrackingReturn => {
|
|
18
|
-
const { sdk } = useAdStage();
|
|
19
|
-
|
|
20
|
-
const trackEvent = useCallback((adId: string, slotId: string, eventType: AdEventType) => {
|
|
21
|
-
if (!sdk) {
|
|
22
|
-
console.warn('SDK not initialized - cannot track event');
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
// SDK의 eventTracker에 직접 접근할 수 없으므로
|
|
28
|
-
// 여기서는 console.log로 대체하거나 SDK에 public 메서드가 있다면 사용
|
|
29
|
-
console.log('Ad Event Tracked:', { adId, slotId, eventType });
|
|
30
|
-
|
|
31
|
-
// 실제 구현에서는 SDK에 trackEvent 메서드가 있다면 사용
|
|
32
|
-
// sdk.trackEvent(adId, slotId, eventType);
|
|
33
|
-
} catch (err) {
|
|
34
|
-
console.error('Failed to track event:', err);
|
|
35
|
-
}
|
|
36
|
-
}, [sdk]);
|
|
37
|
-
|
|
38
|
-
const trackClick = useCallback((adId: string, slotId: string) => {
|
|
39
|
-
trackEvent(adId, slotId, AdEventType.CLICK);
|
|
40
|
-
}, [trackEvent]);
|
|
41
|
-
|
|
42
|
-
const trackImpression = useCallback((adId: string, slotId: string) => {
|
|
43
|
-
trackEvent(adId, slotId, AdEventType.IMPRESSION);
|
|
44
|
-
}, [trackEvent]);
|
|
45
|
-
|
|
46
|
-
const trackView = useCallback((adId: string, slotId: string) => {
|
|
47
|
-
trackEvent(adId, slotId, AdEventType.VIEWABLE);
|
|
48
|
-
}, [trackEvent]);
|
|
49
|
-
|
|
50
|
-
const trackClose = useCallback((adId: string, slotId: string) => {
|
|
51
|
-
trackEvent(adId, slotId, AdEventType.COMPLETED);
|
|
52
|
-
}, [trackEvent]);
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
trackEvent,
|
|
56
|
-
trackClick,
|
|
57
|
-
trackImpression,
|
|
58
|
-
trackView,
|
|
59
|
-
trackClose,
|
|
60
|
-
};
|
|
61
|
-
};
|
package/src/react/index.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import React, { createContext, useContext, useEffect, useState, ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
// 타입만 import해서 circular dependency 방지
|
|
4
|
-
import type { AdStageConfig } from '../../index';
|
|
5
|
-
|
|
6
|
-
// AdStageSDK 클래스 타입 정의 (런타임에는 dynamic import 사용)
|
|
7
|
-
interface AdStageSDKClass {
|
|
8
|
-
init(config: AdStageConfig): AdStageSDKInstance;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface AdStageSDKInstance {
|
|
12
|
-
createSlot: (...args: any[]) => Promise<void>;
|
|
13
|
-
removeSlot?: (slotId: string) => void;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface AdStageContextValue {
|
|
17
|
-
sdk: AdStageSDKInstance | null;
|
|
18
|
-
isLoading: boolean;
|
|
19
|
-
error: string | null;
|
|
20
|
-
isInitialized: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const AdStageContext = createContext<AdStageContextValue>({
|
|
24
|
-
sdk: null,
|
|
25
|
-
isLoading: true,
|
|
26
|
-
error: null,
|
|
27
|
-
isInitialized: false,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
export { AdStageContext };
|
|
31
|
-
|
|
32
|
-
interface AdStageProviderProps {
|
|
33
|
-
config: AdStageConfig;
|
|
34
|
-
children: ReactNode;
|
|
35
|
-
autoInit?: boolean;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const AdStageProvider: React.FC<AdStageProviderProps> = ({
|
|
39
|
-
config,
|
|
40
|
-
children,
|
|
41
|
-
autoInit = true,
|
|
42
|
-
}) => {
|
|
43
|
-
const [sdk, setSdk] = useState<AdStageSDKInstance | null>(null);
|
|
44
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
45
|
-
const [error, setError] = useState<string | null>(null);
|
|
46
|
-
const [isInitialized, setIsInitialized] = useState(false);
|
|
47
|
-
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
const initializeSDK = async () => {
|
|
50
|
-
try {
|
|
51
|
-
setIsLoading(true);
|
|
52
|
-
setError(null);
|
|
53
|
-
|
|
54
|
-
// Dynamic import를 사용해서 circular dependency 방지
|
|
55
|
-
const { AdStageSDK } = await import('../../index');
|
|
56
|
-
|
|
57
|
-
// SDK 인스턴스 생성
|
|
58
|
-
const sdkInstance = AdStageSDK.init(config);
|
|
59
|
-
|
|
60
|
-
setSdk(sdkInstance);
|
|
61
|
-
setIsInitialized(true);
|
|
62
|
-
setIsLoading(false);
|
|
63
|
-
} catch (err) {
|
|
64
|
-
const errorMessage = err instanceof Error ? err.message : 'SDK 초기화 중 오류가 발생했습니다.';
|
|
65
|
-
setError(errorMessage);
|
|
66
|
-
setIsLoading(false);
|
|
67
|
-
console.error('AdStage SDK initialization failed:', err);
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
initializeSDK();
|
|
72
|
-
}, [config.apiKey, config.debug, autoInit]);
|
|
73
|
-
|
|
74
|
-
const value: AdStageContextValue = {
|
|
75
|
-
sdk,
|
|
76
|
-
isLoading,
|
|
77
|
-
error,
|
|
78
|
-
isInitialized,
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
return (
|
|
82
|
-
<AdStageContext.Provider value={value}>
|
|
83
|
-
{children}
|
|
84
|
-
</AdStageContext.Provider>
|
|
85
|
-
);
|
|
86
|
-
};
|