@vynix-org/react-native-ads-sdk 0.1.4 → 0.1.6

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 (49) hide show
  1. package/lib/module/ads-manager/AppOpenAdsManager.js +3 -0
  2. package/lib/module/ads-manager/AppOpenAdsManager.js.map +1 -1
  3. package/lib/module/ads-manager/InterstitialAdsManager.js +26 -3
  4. package/lib/module/ads-manager/InterstitialAdsManager.js.map +1 -1
  5. package/lib/module/ads-manager/NativeAdsManager.js +27 -3
  6. package/lib/module/ads-manager/NativeAdsManager.js.map +1 -1
  7. package/lib/module/ads-manager/RewardedAdsManager.js +26 -2
  8. package/lib/module/ads-manager/RewardedAdsManager.js.map +1 -1
  9. package/lib/module/ads-manager/RewardedInterstitialAdsManager.js +25 -1
  10. package/lib/module/ads-manager/RewardedInterstitialAdsManager.js.map +1 -1
  11. package/lib/module/analytics/AnalyticsManager.js +132 -0
  12. package/lib/module/analytics/AnalyticsManager.js.map +1 -0
  13. package/lib/module/analytics/EventTracking.js +11 -0
  14. package/lib/module/analytics/EventTracking.js.map +1 -0
  15. package/lib/module/analytics/TrackingManager.js +26 -0
  16. package/lib/module/analytics/TrackingManager.js.map +1 -0
  17. package/lib/module/components/BannerAdComponent.js +30 -6
  18. package/lib/module/components/BannerAdComponent.js.map +1 -1
  19. package/lib/module/components/NativeAdComponent.js +49 -80
  20. package/lib/module/components/NativeAdComponent.js.map +1 -1
  21. package/lib/module/components/NativeStyles.js +22 -14
  22. package/lib/module/components/NativeStyles.js.map +1 -1
  23. package/lib/typescript/src/ads-manager/AppOpenAdsManager.d.ts.map +1 -1
  24. package/lib/typescript/src/ads-manager/InterstitialAdsManager.d.ts.map +1 -1
  25. package/lib/typescript/src/ads-manager/NativeAdsManager.d.ts.map +1 -1
  26. package/lib/typescript/src/ads-manager/RewardedAdsManager.d.ts.map +1 -1
  27. package/lib/typescript/src/ads-manager/RewardedInterstitialAdsManager.d.ts.map +1 -1
  28. package/lib/typescript/src/analytics/AnalyticsManager.d.ts +50 -0
  29. package/lib/typescript/src/analytics/AnalyticsManager.d.ts.map +1 -0
  30. package/lib/typescript/src/analytics/EventTracking.d.ts +14 -0
  31. package/lib/typescript/src/analytics/EventTracking.d.ts.map +1 -0
  32. package/lib/typescript/src/analytics/TrackingManager.d.ts +12 -0
  33. package/lib/typescript/src/analytics/TrackingManager.d.ts.map +1 -0
  34. package/lib/typescript/src/components/BannerAdComponent.d.ts.map +1 -1
  35. package/lib/typescript/src/components/NativeAdComponent.d.ts.map +1 -1
  36. package/lib/typescript/src/components/NativeStyles.d.ts +15 -7
  37. package/lib/typescript/src/components/NativeStyles.d.ts.map +1 -1
  38. package/package.json +6 -1
  39. package/src/ads-manager/AppOpenAdsManager.ts +4 -0
  40. package/src/ads-manager/InterstitialAdsManager.ts +29 -3
  41. package/src/ads-manager/NativeAdsManager.ts +31 -2
  42. package/src/ads-manager/RewardedAdsManager.ts +30 -2
  43. package/src/ads-manager/RewardedInterstitialAdsManager.ts +30 -1
  44. package/src/analytics/AnalyticsManager.ts +140 -0
  45. package/src/analytics/EventTracking.ts +14 -0
  46. package/src/analytics/TrackingManager.ts +33 -0
  47. package/src/components/BannerAdComponent.tsx +35 -5
  48. package/src/components/NativeAdComponent.tsx +35 -79
  49. package/src/components/NativeStyles.ts +20 -12
@@ -0,0 +1,140 @@
1
+ import analytics from '@react-native-firebase/analytics';
2
+ import { EventTracking, type EventParams } from './EventTracking';
3
+
4
+ /**
5
+ * Event names cho Ads Analytics
6
+ */
7
+
8
+ /**
9
+ * Analytics Manager để quản lý Firebase Analytics events
10
+ */
11
+ export class AnalyticsManager {
12
+ private static instance: AnalyticsManager;
13
+ private isEnabled = true;
14
+ private isInitialized = false;
15
+ private initPromise: Promise<void> | null = null;
16
+
17
+ private constructor() {}
18
+
19
+ static getInstance(): AnalyticsManager {
20
+ if (!AnalyticsManager.instance) {
21
+ AnalyticsManager.instance = new AnalyticsManager();
22
+ }
23
+ return AnalyticsManager.instance;
24
+ }
25
+
26
+ /**
27
+ * Khởi tạo Analytics Manager
28
+ */
29
+ async initialize(): Promise<void> {
30
+ if (this.isInitialized) {
31
+ return;
32
+ }
33
+
34
+ if (this.initPromise) {
35
+ return this.initPromise;
36
+ }
37
+
38
+ this.initPromise = this.initializeInternal();
39
+ return this.initPromise;
40
+ }
41
+
42
+ private async initializeInternal(): Promise<void> {
43
+ try {
44
+ // Kiểm tra xem analytics có sẵn không
45
+ await analytics().setAnalyticsCollectionEnabled(this.isEnabled);
46
+ this.isInitialized = true;
47
+ console.log('Analytics Manager initialized successfully');
48
+ } catch (error) {
49
+ console.error('Failed to initialize Analytics Manager:', error);
50
+ // Không throw error để không làm gián đoạn app
51
+ this.isInitialized = false;
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Bật/tắt analytics collection
57
+ */
58
+ async setEnabled(enabled: boolean): Promise<void> {
59
+ this.isEnabled = enabled;
60
+ try {
61
+ await analytics().setAnalyticsCollectionEnabled(enabled);
62
+ console.log(`Analytics collection ${enabled ? 'enabled' : 'disabled'}`);
63
+ } catch (error) {
64
+ console.error('Failed to set analytics collection enabled:', error);
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Kiểm tra xem analytics có được bật không
70
+ */
71
+ isAnalyticsEnabled(): boolean {
72
+ return this.isEnabled;
73
+ }
74
+
75
+ /**
76
+ * Log một custom event
77
+ */
78
+ async logEvent(eventName: string, params?: EventParams): Promise<void> {
79
+ if (!this.isEnabled) {
80
+ return;
81
+ }
82
+
83
+ try {
84
+ await this.ensureInitialized();
85
+ await analytics().logEvent(eventName, params);
86
+ console.log(`Analytics event logged: ${eventName}`, params);
87
+ } catch (error) {
88
+ console.error(`Failed to log analytics event ${eventName}:`, error);
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Log ad event với các parameters chuẩn
94
+ */
95
+ async logAdEvent(event: EventTracking, params?: EventParams): Promise<void> {
96
+ await this.logEvent(event, params);
97
+ }
98
+
99
+ async logRequestAdEvent(params?: EventParams): Promise<void> {
100
+ await this.logAdEvent(EventTracking.TRACK_AD_REQUEST, params);
101
+ }
102
+
103
+ async logClickAdEvent(params?: EventParams): Promise<void> {
104
+ await this.logAdEvent(EventTracking.EVENT_CLICK_AD, params);
105
+ }
106
+
107
+ async logRevenueAdEvent(params?: EventParams): Promise<void> {
108
+ await this.logAdEvent(EventTracking.PAID_AD_IMPRESSION, params);
109
+ await this.logAdEvent(EventTracking.EVENT_PURCHASE, params);
110
+ }
111
+
112
+ async logAdLoadedEvent(params?: EventParams): Promise<void> {
113
+ await this.logAdEvent(EventTracking.EVENT_AD_LOADED, params);
114
+ }
115
+
116
+ /**
117
+ * Reset analytics data
118
+ */
119
+ async resetAnalyticsData(): Promise<void> {
120
+ try {
121
+ await this.ensureInitialized();
122
+ await analytics().resetAnalyticsData();
123
+ console.log('Analytics data reset');
124
+ } catch (error) {
125
+ console.error('Failed to reset analytics data:', error);
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Đảm bảo analytics đã được khởi tạo
131
+ */
132
+ private async ensureInitialized(): Promise<void> {
133
+ if (!this.isInitialized) {
134
+ await this.initialize();
135
+ }
136
+ }
137
+ }
138
+
139
+ // Singleton instance
140
+ export const analyticsManager = AnalyticsManager.getInstance();
@@ -0,0 +1,14 @@
1
+ export enum EventTracking {
2
+ TRACK_AD_REQUEST = 'track_ad_request',
3
+ PAID_AD_IMPRESSION = 'paid_ad_impression_value',
4
+ EVENT_CLICK_AD = 'event_user_click_ads',
5
+ EVENT_AD_LOADED = 'track_ad_matched_request',
6
+ EVENT_PURCHASE = 'purchase',
7
+ }
8
+
9
+ export interface EventParams {
10
+ adUnitId?: string;
11
+ adFormat?: string;
12
+ currency?: string;
13
+ value?: number;
14
+ }
@@ -0,0 +1,33 @@
1
+ import { analyticsManager } from './AnalyticsManager';
2
+ import type { EventParams } from './EventTracking';
3
+
4
+ export class TrackingManager {
5
+ private static instance: TrackingManager;
6
+
7
+ private constructor() {}
8
+
9
+ static getInstance(): TrackingManager {
10
+ if (!TrackingManager.instance) {
11
+ TrackingManager.instance = new TrackingManager();
12
+ }
13
+ return TrackingManager.instance;
14
+ }
15
+
16
+ async onTrackingRequestAd(params?: EventParams) {
17
+ await analyticsManager.logRequestAdEvent(params);
18
+ }
19
+
20
+ async onTrackingClickAd(params?: EventParams) {
21
+ await analyticsManager.logClickAdEvent(params);
22
+ }
23
+
24
+ async onTrackingRevenueAd(params?: EventParams) {
25
+ await analyticsManager.logRevenueAdEvent(params);
26
+ }
27
+
28
+ async onTrackingAdLoaded(params?: EventParams) {
29
+ await analyticsManager.logAdLoadedEvent(params);
30
+ }
31
+ }
32
+
33
+ export const trackingManager = TrackingManager.getInstance();
@@ -1,12 +1,17 @@
1
1
  import React, { useEffect, useState, useRef } from 'react';
2
2
  import { View, StyleSheet } from 'react-native';
3
- import { BannerAd, type RequestOptions } from 'react-native-google-mobile-ads';
3
+ import {
4
+ BannerAd,
5
+ type PaidEvent,
6
+ type RequestOptions,
7
+ } from 'react-native-google-mobile-ads';
4
8
  import {
5
9
  Placeholder,
6
10
  PlaceholderMedia,
7
11
  PlaceholderLine,
8
12
  Fade,
9
13
  } from 'rn-placeholder';
14
+ import { trackingManager } from '../analytics/TrackingManager';
10
15
 
11
16
  interface BannerAdComponentProps {
12
17
  adId: string;
@@ -37,7 +42,7 @@ export const BannerAdComponent: React.FC<BannerAdComponentProps> = ({
37
42
  adId,
38
43
  adHighpriorityId,
39
44
  style,
40
- size = 'BANNER',
45
+ size = 'ANCHORED_ADAPTIVE_BANNER',
41
46
  onAdLoaded,
42
47
  onAdFailedToLoad,
43
48
  onAdOpened,
@@ -54,6 +59,7 @@ export const BannerAdComponent: React.FC<BannerAdComponentProps> = ({
54
59
  const [isLoaded, setIsLoaded] = useState(false);
55
60
  const [error, setError] = useState<string | null>(null);
56
61
  const [shouldRender, setShouldRender] = useState(false);
62
+ const [height, setHeight] = useState<number>(50);
57
63
  const bannerRef = useRef<any>(null);
58
64
 
59
65
  const [currentAdId, setCurrentAdId] = useState<string>(
@@ -71,10 +77,15 @@ export const BannerAdComponent: React.FC<BannerAdComponentProps> = ({
71
77
  }, [adHighpriorityId]);
72
78
 
73
79
  const handleAdLoaded = () => {
80
+ setHeight(50);
74
81
  setIsLoaded(true);
75
82
  setError(null);
76
83
  console.log('PreloadedBannerAd loaded:', currentAdId);
77
84
  onAdLoaded?.();
85
+ trackingManager.onTrackingRequestAd({
86
+ adUnitId: currentAdId,
87
+ adFormat: 'Banner',
88
+ });
78
89
  };
79
90
 
80
91
  const handleAdFailedToLoad = (error: Error) => {
@@ -99,7 +110,7 @@ export const BannerAdComponent: React.FC<BannerAdComponentProps> = ({
99
110
  return; // Không gọi onAdFailedToLoad vì sẽ thử lại
100
111
  }
101
112
 
102
- // Nếu đã thử cả 2 hoặc không có high priority, hiển thị error
113
+ setHeight(0);
103
114
  setError(error.message);
104
115
  onAdFailedToLoad?.(error);
105
116
  };
@@ -117,11 +128,29 @@ export const BannerAdComponent: React.FC<BannerAdComponentProps> = ({
117
128
  const handleAdClicked = () => {
118
129
  console.log('PreloadedBannerAd clicked');
119
130
  onAdClicked?.();
131
+ trackingManager.onTrackingClickAd({
132
+ adUnitId: currentAdId,
133
+ adFormat: 'Banner',
134
+ });
120
135
  };
121
136
 
122
137
  const handleAdImpression = () => {
123
138
  console.log('PreloadedBannerAd impression');
124
139
  onAdImpression?.();
140
+ trackingManager.onTrackingAdLoaded({
141
+ adUnitId: currentAdId,
142
+ adFormat: 'Banner',
143
+ });
144
+ };
145
+
146
+ const handlePaid = (paid: PaidEvent) => {
147
+ console.log('PreloadedBannerAd paid:', paid);
148
+ trackingManager.onTrackingRevenueAd({
149
+ adUnitId: currentAdId,
150
+ adFormat: 'Banner',
151
+ currency: paid.currency,
152
+ value: paid.value,
153
+ });
125
154
  };
126
155
 
127
156
  if (!shouldRender) {
@@ -148,7 +177,7 @@ export const BannerAdComponent: React.FC<BannerAdComponentProps> = ({
148
177
 
149
178
  {error && showError && <View />}
150
179
 
151
- <View style={{ minHeight: 50 }}>
180
+ <View style={{ minHeight: height }}>
152
181
  <BannerAd
153
182
  key={currentAdId}
154
183
  ref={bannerRef}
@@ -161,6 +190,7 @@ export const BannerAdComponent: React.FC<BannerAdComponentProps> = ({
161
190
  onAdClicked={handleAdClicked}
162
191
  onAdImpression={handleAdImpression}
163
192
  requestOptions={requestOptions}
193
+ onPaid={(paid) => handlePaid(paid)}
164
194
  />
165
195
  </View>
166
196
  </View>
@@ -181,7 +211,7 @@ const styles = StyleSheet.create({
181
211
  justifyContent: 'center',
182
212
  backgroundColor: 'rgba(255, 255, 255, 0.9)',
183
213
  paddingHorizontal: 20,
184
- paddingVertical: 10,
214
+ paddingVertical: 12,
185
215
  borderRadius: 8,
186
216
  },
187
217
  loadingText: {
@@ -3,7 +3,6 @@ import {
3
3
  View,
4
4
  Text,
5
5
  ActivityIndicator,
6
- TouchableOpacity,
7
6
  type ViewStyle,
8
7
  type TextStyle,
9
8
  } from 'react-native';
@@ -17,6 +16,7 @@ import {
17
16
  import { useNativeAd } from '../hook/useNativeAd';
18
17
  import type { AdInstance } from '../types/ads-types';
19
18
  import { styles } from './NativeStyles';
19
+ import { Image } from 'react-native';
20
20
 
21
21
  interface NativeAdComponentProps {
22
22
  adKey: string;
@@ -51,11 +51,8 @@ export const NativeAdComponent: React.FC<NativeAdComponentProps> = ({
51
51
  adBadgeStyles,
52
52
  headlineStyles,
53
53
  bodyStyles,
54
- ratingStyles,
55
- priceStyles,
56
- storeStyles,
57
54
  }) => {
58
- const { ad, isLoading, error, isLoaded, loadAd } = useNativeAd({
55
+ const { ad, isLoading, error, isLoaded } = useNativeAd({
59
56
  adKey,
60
57
  adId,
61
58
  autoLoad,
@@ -80,27 +77,12 @@ export const NativeAdComponent: React.FC<NativeAdComponentProps> = ({
80
77
 
81
78
  // Render error state
82
79
  if (error) {
83
- return (
84
- <View style={[styles.wrapper, style]}>
85
- <View style={[styles.container, styles.centerContent]}>
86
- <Text style={styles.errorText}>Lỗi: {error}</Text>
87
- <TouchableOpacity onPress={() => loadAd()} style={styles.retryButton}>
88
- <Text style={styles.retryText}>Thử lại</Text>
89
- </TouchableOpacity>
90
- </View>
91
- </View>
92
- );
80
+ return null;
93
81
  }
94
82
 
95
83
  // Render empty state
96
84
  if (!isLoaded || !ad?.data?.nativeAd) {
97
- return (
98
- <View style={[styles.wrapper, style]}>
99
- <View style={[styles.container, styles.centerContent]}>
100
- <Text style={styles.emptyText}>Không có quảng cáo</Text>
101
- </View>
102
- </View>
103
- );
85
+ return null;
104
86
  }
105
87
 
106
88
  const nativeAd = ad.data.nativeAd as NativeAd;
@@ -110,9 +92,6 @@ export const NativeAdComponent: React.FC<NativeAdComponentProps> = ({
110
92
  <NativeAdView nativeAd={nativeAd} style={[styles.container]}>
111
93
  {/* Ad Badge và Advertiser */}
112
94
  <View style={styles.adHeader}>
113
- {/* <NativeAsset assetType={NativeAssetType.ADVERTISER}> */}
114
- <Text style={[styles.adBadge, adBadgeStyles]}>Ad</Text>
115
- {/* </NativeAsset> */}
116
95
  {nativeAd.advertiser && (
117
96
  <NativeAsset assetType={NativeAssetType.ADVERTISER}>
118
97
  <Text style={styles.advertiserText} numberOfLines={1}>
@@ -122,6 +101,14 @@ export const NativeAdComponent: React.FC<NativeAdComponentProps> = ({
122
101
  )}
123
102
  </View>
124
103
 
104
+ {nativeAd.callToAction && (
105
+ <NativeAsset assetType={NativeAssetType.CALL_TO_ACTION}>
106
+ <View style={[styles.ctaButton, buttonActionStyles]}>
107
+ <Text style={styles.ctaText}>{nativeAd.callToAction}</Text>
108
+ </View>
109
+ </NativeAsset>
110
+ )}
111
+
125
112
  {/* Media View - Hiển thị ảnh hoặc video */}
126
113
  {((nativeAd.images?.length && nativeAd.images.length > 0) ||
127
114
  nativeAd.mediaContent) && (
@@ -137,71 +124,40 @@ export const NativeAdComponent: React.FC<NativeAdComponentProps> = ({
137
124
 
138
125
  {/* Ad Content */}
139
126
  <View style={styles.contentContainer}>
140
- {/* Headline */}
141
- {nativeAd.headline && (
142
- <NativeAsset assetType={NativeAssetType.HEADLINE}>
143
- <Text style={[styles.headline, headlineStyles]} numberOfLines={2}>
144
- {nativeAd.headline}
145
- </Text>
146
- </NativeAsset>
147
- )}
148
-
149
- {/* Body */}
150
- {nativeAd.body && (
151
- <NativeAsset assetType={NativeAssetType.BODY}>
152
- <Text style={[styles.bodyText, bodyStyles]} numberOfLines={3}>
153
- {nativeAd.body}
154
- </Text>
127
+ {nativeAd.icon && (
128
+ <NativeAsset assetType={NativeAssetType.ICON}>
129
+ <View style={styles.iconContainer}>
130
+ <Image
131
+ source={{ uri: nativeAd.icon?.url }}
132
+ style={styles.icon}
133
+ />
134
+ </View>
155
135
  </NativeAsset>
156
136
  )}
157
-
158
- {/* Rating, Price, Store Row */}
159
- <View style={styles.infoRow}>
160
- {/* Star Rating */}
161
- {nativeAd.starRating !== null &&
162
- nativeAd.starRating !== undefined && (
163
- <NativeAsset assetType={NativeAssetType.STAR_RATING}>
164
- <Text style={[styles.ratingText, ratingStyles]}>
165
- ⭐ {nativeAd.starRating.toFixed(1)}
137
+ <View style={{ flex: 1 }}>
138
+ <View style={styles.vHeader}>
139
+ <Text style={[styles.adBadge, adBadgeStyles]}>Ad</Text>
140
+ {nativeAd.headline && (
141
+ <NativeAsset assetType={NativeAssetType.HEADLINE}>
142
+ <Text
143
+ style={[styles.headline, headlineStyles]}
144
+ numberOfLines={1}
145
+ >
146
+ {nativeAd.headline}
166
147
  </Text>
167
148
  </NativeAsset>
168
149
  )}
150
+ </View>
169
151
 
170
- {/* Price */}
171
- {nativeAd.price && (
172
- <NativeAsset assetType={NativeAssetType.PRICE}>
173
- <Text style={[styles.priceText, priceStyles]}>
174
- {nativeAd.price}
175
- </Text>
176
- </NativeAsset>
177
- )}
178
-
179
- {/* Store */}
180
- {nativeAd.store && (
181
- <NativeAsset assetType={NativeAssetType.STORE}>
182
- <Text style={[styles.storeText, storeStyles]} numberOfLines={1}>
183
- {nativeAd.store}
152
+ {nativeAd.body && (
153
+ <NativeAsset assetType={NativeAssetType.BODY}>
154
+ <Text numberOfLines={2} style={[styles.bodyText, bodyStyles]}>
155
+ {nativeAd.body}
184
156
  </Text>
185
157
  </NativeAsset>
186
158
  )}
187
159
  </View>
188
-
189
- {/* Call To Action Button */}
190
- {nativeAd.callToAction && (
191
- <NativeAsset assetType={NativeAssetType.CALL_TO_ACTION}>
192
- <View style={[styles.ctaButton, buttonActionStyles]}>
193
- <Text style={styles.ctaText}>{nativeAd.callToAction}</Text>
194
- </View>
195
- </NativeAsset>
196
- )}
197
160
  </View>
198
-
199
- {/* Icon */}
200
- {/* {nativeAd.icon && (
201
- <NativeAsset assetType={NativeAssetType.ICON}>
202
- <View style={styles.iconContainer} />
203
- </NativeAsset>
204
- )} */}
205
161
  </NativeAdView>
206
162
  </View>
207
163
  );
@@ -55,13 +55,14 @@ export const styles = StyleSheet.create({
55
55
  backgroundColor: '#F9F9F9',
56
56
  },
57
57
  adBadge: {
58
- backgroundColor: '#FFCC00',
58
+ backgroundColor: '#57BF87',
59
59
  paddingHorizontal: 6,
60
60
  paddingVertical: 2,
61
61
  borderRadius: 3,
62
62
  fontSize: 10,
63
+ marginEnd: 10,
63
64
  fontWeight: '700',
64
- color: '#666',
65
+ color: '#fff',
65
66
  },
66
67
  advertiserText: {
67
68
  fontSize: 11,
@@ -75,23 +76,22 @@ export const styles = StyleSheet.create({
75
76
  minHeight: 180,
76
77
  maxHeight: 250,
77
78
  alignSelf: 'center',
78
- backgroundColor: '#F0F0F0',
79
79
  },
80
80
  contentContainer: {
81
+ flexDirection: 'row',
82
+ alignItems: 'center',
81
83
  padding: 12,
82
84
  },
83
85
  headline: {
84
86
  fontSize: 16,
85
87
  fontWeight: '700',
86
88
  color: '#000',
87
- marginBottom: 6,
88
89
  lineHeight: 22,
89
90
  },
90
91
  bodyText: {
91
92
  fontSize: 13,
92
93
  color: '#666',
93
94
  lineHeight: 18,
94
- marginBottom: 10,
95
95
  },
96
96
  infoRow: {
97
97
  flexDirection: 'row',
@@ -118,7 +118,8 @@ export const styles = StyleSheet.create({
118
118
  ctaButton: {
119
119
  backgroundColor: '#007AFF',
120
120
  paddingVertical: 10,
121
- paddingHorizontal: 20,
121
+ marginHorizontal: 20,
122
+ marginBottom: 10,
122
123
  borderRadius: 6,
123
124
  alignItems: 'center',
124
125
  justifyContent: 'center',
@@ -129,13 +130,20 @@ export const styles = StyleSheet.create({
129
130
  color: '#FFFFFF',
130
131
  },
131
132
  iconContainer: {
132
- position: 'absolute',
133
- top: 8,
134
- right: 8,
135
- width: 36,
136
- height: 36,
137
- borderRadius: 18,
133
+ width: 40,
134
+ height: 40,
135
+ borderRadius: 8,
136
+ marginEnd: 10,
138
137
  overflow: 'hidden',
139
138
  backgroundColor: '#F0F0F0',
140
139
  },
140
+ icon: {
141
+ width: '100%',
142
+ height: '100%',
143
+ resizeMode: 'cover',
144
+ },
145
+ vHeader: {
146
+ flexDirection: 'row',
147
+ alignItems: 'center',
148
+ },
141
149
  });