@raxonltd/raxon-core 1.0.4 → 1.0.8
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/core/feature/analytic-event/analytic.event.api.d.ts +13 -0
- package/dist/core/feature/analytic-event/analytic.event.api.d.ts.map +1 -0
- package/dist/core/feature/analytic-event/analytic.event.api.js +10 -0
- package/dist/core/feature/analytic-event/analytic.event.context.d.ts +8 -5
- package/dist/core/feature/analytic-event/analytic.event.context.d.ts.map +1 -1
- package/dist/core/feature/analytic-event/analytic.event.context.js +58 -84
- package/dist/core/feature/analytic-event/analytic.event.util.d.ts +8 -0
- package/dist/core/feature/analytic-event/analytic.event.util.d.ts.map +1 -0
- package/dist/core/feature/analytic-event/analytic.event.util.js +39 -0
- package/dist/core/feature/analytic-event/use.analytic.auto.d.ts +13 -0
- package/dist/core/feature/analytic-event/use.analytic.auto.d.ts.map +1 -0
- package/dist/core/feature/analytic-event/use.analytic.auto.js +81 -0
- package/dist/core/raxon.context.d.ts +3 -1
- package/dist/core/raxon.context.d.ts.map +1 -1
- package/dist/core/raxon.context.js +11 -12
- package/dist/core/util/nexine.axios.js +22 -0
- package/dist/core/view/view.checkout.d.ts +5 -1
- package/dist/core/view/view.checkout.d.ts.map +1 -1
- package/dist/core/view/view.checkout.js +265 -10
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AnalyticEventType } from '../../interface/prisma.interface';
|
|
2
|
+
export interface ProductAnalyticPayload {
|
|
3
|
+
productId: string;
|
|
4
|
+
variantId?: string | null;
|
|
5
|
+
eventType?: AnalyticEventType;
|
|
6
|
+
}
|
|
7
|
+
export interface EmailClickedAnalyticPayload {
|
|
8
|
+
trackingCode: string;
|
|
9
|
+
eventType: AnalyticEventType.EMAIL_CLICKED;
|
|
10
|
+
}
|
|
11
|
+
export type AnalyticEventPayload = ProductAnalyticPayload | EmailClickedAnalyticPayload;
|
|
12
|
+
export declare function sendAnalyticEvents(events: AnalyticEventPayload[]): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=analytic.event.api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytic.event.api.d.ts","sourceRoot":"","sources":["../../../../core/feature/analytic-event/analytic.event.api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAGtE,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,iBAAiB,CAAC;CAC/B;AAED,MAAM,WAAW,2BAA2B;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,iBAAiB,CAAC,aAAa,CAAC;CAC5C;AAED,MAAM,MAAM,oBAAoB,GAAG,sBAAsB,GAAG,2BAA2B,CAAC;AAExF,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,oBAAoB,EAAE,iBAUtE"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AnalyticEventType } from '../../interface/prisma.interface';
|
|
2
|
+
import { nexineAxios } from '../../util/nexine.axios';
|
|
3
|
+
export async function sendAnalyticEvents(events) {
|
|
4
|
+
if (events.length === 0)
|
|
5
|
+
return;
|
|
6
|
+
await nexineAxios.patch('/customer/analytic-event', events.map((event) => ({
|
|
7
|
+
...event,
|
|
8
|
+
eventType: 'eventType' in event && event.eventType ? event.eventType : AnalyticEventType.VIEW,
|
|
9
|
+
})));
|
|
10
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
interface
|
|
2
|
+
interface ProductAnalyticEvent {
|
|
3
3
|
productId: string;
|
|
4
4
|
variantId?: string | null;
|
|
5
5
|
}
|
|
@@ -7,13 +7,16 @@ interface EmailClickedEvent {
|
|
|
7
7
|
tcx: string;
|
|
8
8
|
}
|
|
9
9
|
interface AnalyticEventContextType {
|
|
10
|
-
trackProductView: (event:
|
|
11
|
-
trackProductClick: (event:
|
|
10
|
+
trackProductView: (event: ProductAnalyticEvent) => void;
|
|
11
|
+
trackProductClick: (event: ProductAnalyticEvent) => void;
|
|
12
12
|
trackEmailClicked: (event: EmailClickedEvent) => void;
|
|
13
13
|
}
|
|
14
|
-
export
|
|
14
|
+
export interface AnalyticEventProviderProps {
|
|
15
15
|
children: React.ReactNode;
|
|
16
|
-
|
|
16
|
+
productPathPrefix?: string;
|
|
17
|
+
autoTrack?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare const AnalyticEventProvider: ({ children, productPathPrefix, autoTrack, }: AnalyticEventProviderProps) => React.JSX.Element;
|
|
17
20
|
export declare const useAnalyticEvent: () => AnalyticEventContextType;
|
|
18
21
|
export {};
|
|
19
22
|
//# sourceMappingURL=analytic.event.context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytic.event.context.d.ts","sourceRoot":"","sources":["../../../../core/feature/analytic-event/analytic.event.context.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"analytic.event.context.d.ts","sourceRoot":"","sources":["../../../../core/feature/analytic-event/analytic.event.context.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAoE,MAAM,OAAO,CAAC;AAMzF,UAAU,oBAAoB;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,UAAU,iBAAiB;IACzB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,UAAU,wBAAwB;IAChC,gBAAgB,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACxD,iBAAiB,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACzD,iBAAiB,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CACvD;AAID,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,qBAAqB,GAAI,6CAInC,0BAA0B,sBAwI5B,CAAC;AAEF,eAAO,MAAM,gBAAgB,gCAM5B,CAAC"}
|
|
@@ -1,70 +1,37 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { createContext, useContext, useEffect, useRef } from 'react';
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useRef } from 'react';
|
|
4
4
|
import { useSearchParams, useRouter } from 'next/navigation';
|
|
5
5
|
import { AnalyticEventType } from '../../interface/prisma.interface';
|
|
6
|
+
import { sendAnalyticEvents } from './analytic.event.api';
|
|
7
|
+
import { useAnalyticAutoTrack } from './use.analytic.auto';
|
|
6
8
|
const AnalyticEventContext = createContext(undefined);
|
|
7
|
-
export const AnalyticEventProvider = ({ children }) => {
|
|
9
|
+
export const AnalyticEventProvider = ({ children, productPathPrefix = '/urunler', autoTrack = true, }) => {
|
|
8
10
|
const bufferRef = useRef([]);
|
|
9
11
|
const timeoutRef = useRef(null);
|
|
10
12
|
const searchParams = useSearchParams();
|
|
11
13
|
const router = useRouter();
|
|
12
14
|
const tcxProcessedRef = useRef(false);
|
|
13
|
-
const flush = async () => {
|
|
15
|
+
const flush = useCallback(async () => {
|
|
14
16
|
const events = [...bufferRef.current];
|
|
15
17
|
if (events.length === 0)
|
|
16
18
|
return;
|
|
17
|
-
// Send copy, clear original buffer immediately to avoid race conditions if possible
|
|
18
|
-
// (though in JS single thread it's mostly fine, but async operations...)
|
|
19
19
|
bufferRef.current = [];
|
|
20
20
|
try {
|
|
21
|
-
await
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
body: JSON.stringify(events),
|
|
27
|
-
keepalive: true,
|
|
28
|
-
});
|
|
21
|
+
await sendAnalyticEvents(events.map((event) => ({
|
|
22
|
+
productId: event.productId,
|
|
23
|
+
variantId: event.variantId,
|
|
24
|
+
eventType: AnalyticEventType.VIEW,
|
|
25
|
+
})));
|
|
29
26
|
}
|
|
30
|
-
catch (
|
|
31
|
-
console.error('Failed to send product events',
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.error('Failed to send product view events', error);
|
|
32
29
|
}
|
|
33
|
-
};
|
|
34
|
-
const
|
|
35
|
-
try {
|
|
36
|
-
await fetch('/api/analytic-event', {
|
|
37
|
-
method: 'POST',
|
|
38
|
-
headers: {
|
|
39
|
-
'Content-Type': 'application/json',
|
|
40
|
-
},
|
|
41
|
-
body: JSON.stringify([
|
|
42
|
-
{
|
|
43
|
-
trackingCode: tcx,
|
|
44
|
-
eventType: AnalyticEventType.EMAIL_CLICKED,
|
|
45
|
-
},
|
|
46
|
-
]),
|
|
47
|
-
keepalive: true,
|
|
48
|
-
});
|
|
49
|
-
// İşlem tamamlandıktan sonra URL'den tcx parametresini kaldır
|
|
50
|
-
removeTcxFromUrl();
|
|
51
|
-
}
|
|
52
|
-
catch (e) {
|
|
53
|
-
console.error('Failed to send email clicked event', e);
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
const removeTcxFromUrl = () => {
|
|
57
|
-
const currentUrl = new URL(window.location.href);
|
|
58
|
-
if (currentUrl.searchParams.has('tcx')) {
|
|
59
|
-
currentUrl.searchParams.delete('tcx');
|
|
60
|
-
router.replace(currentUrl.pathname + currentUrl.search, { scroll: false });
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
const trackProductView = (event) => {
|
|
30
|
+
}, []);
|
|
31
|
+
const trackProductView = useCallback((event) => {
|
|
64
32
|
if (!event.productId)
|
|
65
33
|
return;
|
|
66
|
-
|
|
67
|
-
const exists = bufferRef.current.some(e => e.productId === event.productId && e.variantId === event.variantId);
|
|
34
|
+
const exists = bufferRef.current.some((item) => item.productId === event.productId && item.variantId === event.variantId);
|
|
68
35
|
if (!exists) {
|
|
69
36
|
bufferRef.current.push(event);
|
|
70
37
|
}
|
|
@@ -74,42 +41,56 @@ export const AnalyticEventProvider = ({ children }) => {
|
|
|
74
41
|
timeoutRef.current = null;
|
|
75
42
|
}, 2000);
|
|
76
43
|
}
|
|
77
|
-
};
|
|
78
|
-
const trackProductClick = (event) => {
|
|
44
|
+
}, [flush]);
|
|
45
|
+
const trackProductClick = useCallback((event) => {
|
|
79
46
|
if (!event.productId)
|
|
80
47
|
return;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
48
|
+
sendAnalyticEvents([
|
|
49
|
+
{
|
|
50
|
+
productId: event.productId,
|
|
51
|
+
variantId: event.variantId,
|
|
52
|
+
eventType: AnalyticEventType.CLICKED,
|
|
85
53
|
},
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
productId: event.productId,
|
|
89
|
-
variantId: event.variantId,
|
|
90
|
-
eventType: AnalyticEventType.CLICKED,
|
|
91
|
-
},
|
|
92
|
-
]),
|
|
93
|
-
keepalive: true,
|
|
94
|
-
}).catch((e) => {
|
|
95
|
-
console.error('Failed to send product click event', e);
|
|
54
|
+
]).catch((error) => {
|
|
55
|
+
console.error('Failed to send product click event', error);
|
|
96
56
|
});
|
|
97
|
-
};
|
|
98
|
-
const
|
|
57
|
+
}, []);
|
|
58
|
+
const removeTcxFromUrl = useCallback(() => {
|
|
59
|
+
const currentUrl = new URL(window.location.href);
|
|
60
|
+
if (!currentUrl.searchParams.has('tcx'))
|
|
61
|
+
return;
|
|
62
|
+
currentUrl.searchParams.delete('tcx');
|
|
63
|
+
router.replace(currentUrl.pathname + currentUrl.search, { scroll: false });
|
|
64
|
+
}, [router]);
|
|
65
|
+
const trackEmailClicked = useCallback((event) => {
|
|
99
66
|
if (!event.tcx)
|
|
100
67
|
return;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
68
|
+
sendAnalyticEvents([
|
|
69
|
+
{
|
|
70
|
+
trackingCode: event.tcx,
|
|
71
|
+
eventType: AnalyticEventType.EMAIL_CLICKED,
|
|
72
|
+
},
|
|
73
|
+
])
|
|
74
|
+
.then(() => removeTcxFromUrl())
|
|
75
|
+
.catch((error) => {
|
|
76
|
+
console.error('Failed to send email clicked event', error);
|
|
77
|
+
});
|
|
78
|
+
}, [removeTcxFromUrl]);
|
|
79
|
+
useAnalyticAutoTrack({
|
|
80
|
+
enabled: autoTrack,
|
|
81
|
+
productPathPrefix,
|
|
82
|
+
trackProductView,
|
|
83
|
+
trackProductClick,
|
|
84
|
+
});
|
|
104
85
|
useEffect(() => {
|
|
105
86
|
if (tcxProcessedRef.current)
|
|
106
87
|
return;
|
|
107
88
|
const tcx = searchParams.get('tcx');
|
|
108
|
-
if (tcx)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
}, [searchParams]);
|
|
89
|
+
if (!tcx)
|
|
90
|
+
return;
|
|
91
|
+
tcxProcessedRef.current = true;
|
|
92
|
+
trackEmailClicked({ tcx });
|
|
93
|
+
}, [searchParams, trackEmailClicked]);
|
|
113
94
|
useEffect(() => {
|
|
114
95
|
const handleUnload = () => {
|
|
115
96
|
if (timeoutRef.current) {
|
|
@@ -120,13 +101,6 @@ export const AnalyticEventProvider = ({ children }) => {
|
|
|
120
101
|
};
|
|
121
102
|
const handleVisibilityChange = () => {
|
|
122
103
|
if (document.visibilityState === 'hidden') {
|
|
123
|
-
// If user switches tab, maybe flush?
|
|
124
|
-
// User asked for "session end" or "2s".
|
|
125
|
-
// Visibility hidden is good practice to ensure data is saved.
|
|
126
|
-
// But if they come back, we just start a new batch.
|
|
127
|
-
// Let's keep the timeout if it's running, but flush if tab is closing/hiding?
|
|
128
|
-
// Actually, if we flush on hidden, we might send partial batches more often than 2s if user switches tabs a lot.
|
|
129
|
-
// But better safe than sorry for analytics.
|
|
130
104
|
handleUnload();
|
|
131
105
|
}
|
|
132
106
|
};
|
|
@@ -139,13 +113,13 @@ export const AnalyticEventProvider = ({ children }) => {
|
|
|
139
113
|
clearTimeout(timeoutRef.current);
|
|
140
114
|
}
|
|
141
115
|
};
|
|
142
|
-
}, []);
|
|
143
|
-
return _jsx(AnalyticEventContext.Provider, { value: { trackProductView, trackProductClick, trackEmailClicked }, children: children });
|
|
116
|
+
}, [flush]);
|
|
117
|
+
return (_jsx(AnalyticEventContext.Provider, { value: { trackProductView, trackProductClick, trackEmailClicked }, children: children }));
|
|
144
118
|
};
|
|
145
119
|
export const useAnalyticEvent = () => {
|
|
146
120
|
const context = useContext(AnalyticEventContext);
|
|
147
121
|
if (!context) {
|
|
148
|
-
throw new Error('useAnalyticEvent must be used within
|
|
122
|
+
throw new Error('useAnalyticEvent must be used within an AnalyticEventProvider');
|
|
149
123
|
}
|
|
150
124
|
return context;
|
|
151
125
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function escapeRegExp(value: string): string;
|
|
2
|
+
export declare function buildProductPathPattern(productPathPrefix: string): RegExp;
|
|
3
|
+
export declare function extractProductIdFromHref(href: string, productPathPrefix: string): string;
|
|
4
|
+
export declare function readProductFromElement(element: Element, productPathPrefix: string): {
|
|
5
|
+
productId: string;
|
|
6
|
+
variantId: string;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=analytic.event.util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytic.event.util.d.ts","sourceRoot":"","sources":["../../../../core/feature/analytic-event/analytic.event.util.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,UAEzC;AAED,wBAAgB,uBAAuB,CAAC,iBAAiB,EAAE,MAAM,UAGhE;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,UAW/E;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM;;;EAmBjF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export function escapeRegExp(value) {
|
|
2
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
3
|
+
}
|
|
4
|
+
export function buildProductPathPattern(productPathPrefix) {
|
|
5
|
+
const prefix = productPathPrefix.replace(/\/$/, '');
|
|
6
|
+
return new RegExp(`${escapeRegExp(prefix)}/([^/?#]+)`);
|
|
7
|
+
}
|
|
8
|
+
export function extractProductIdFromHref(href, productPathPrefix) {
|
|
9
|
+
if (!href)
|
|
10
|
+
return null;
|
|
11
|
+
try {
|
|
12
|
+
const url = href.startsWith('http') ? new URL(href) : new URL(href, window.location.origin);
|
|
13
|
+
const match = url.pathname.match(buildProductPathPattern(productPathPrefix));
|
|
14
|
+
return match?.[1] ?? null;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
const match = href.match(buildProductPathPattern(productPathPrefix));
|
|
18
|
+
return match?.[1] ?? null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function readProductFromElement(element, productPathPrefix) {
|
|
22
|
+
const trackedElement = element.closest('[data-raxon-product-id]');
|
|
23
|
+
if (trackedElement) {
|
|
24
|
+
const productId = trackedElement.getAttribute('data-raxon-product-id');
|
|
25
|
+
if (!productId)
|
|
26
|
+
return null;
|
|
27
|
+
return {
|
|
28
|
+
productId,
|
|
29
|
+
variantId: trackedElement.getAttribute('data-raxon-variant-id'),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const link = element.closest('a[href]');
|
|
33
|
+
if (!link)
|
|
34
|
+
return null;
|
|
35
|
+
const productId = extractProductIdFromHref(link.getAttribute('href') || '', productPathPrefix);
|
|
36
|
+
if (!productId)
|
|
37
|
+
return null;
|
|
38
|
+
return { productId, variantId: null };
|
|
39
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface ProductAnalyticEvent {
|
|
2
|
+
productId: string;
|
|
3
|
+
variantId?: string | null;
|
|
4
|
+
}
|
|
5
|
+
interface UseAnalyticAutoTrackOptions {
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
productPathPrefix: string;
|
|
8
|
+
trackProductView: (event: ProductAnalyticEvent) => void;
|
|
9
|
+
trackProductClick: (event: ProductAnalyticEvent) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function useAnalyticAutoTrack({ enabled, productPathPrefix, trackProductView, trackProductClick, }: UseAnalyticAutoTrackOptions): void;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=use.analytic.auto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use.analytic.auto.d.ts","sourceRoot":"","sources":["../../../../core/feature/analytic-event/use.analytic.auto.tsx"],"names":[],"mappings":"AAMA,UAAU,oBAAoB;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,UAAU,2BAA2B;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACxD,iBAAiB,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;CAC1D;AAED,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,GAClB,EAAE,2BAA2B,QA0F7B"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
import { usePathname } from 'next/navigation';
|
|
4
|
+
import { buildProductPathPattern, extractProductIdFromHref, readProductFromElement } from './analytic.event.util';
|
|
5
|
+
export function useAnalyticAutoTrack({ enabled, productPathPrefix, trackProductView, trackProductClick, }) {
|
|
6
|
+
const pathname = usePathname();
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (!enabled)
|
|
9
|
+
return;
|
|
10
|
+
const productId = pathname.match(buildProductPathPattern(productPathPrefix))?.[1];
|
|
11
|
+
if (productId) {
|
|
12
|
+
trackProductView({ productId });
|
|
13
|
+
}
|
|
14
|
+
}, [enabled, pathname, productPathPrefix, trackProductView]);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (!enabled || typeof window === 'undefined')
|
|
17
|
+
return;
|
|
18
|
+
const viewedElements = new WeakSet();
|
|
19
|
+
const trackVisibleElement = (element) => {
|
|
20
|
+
if (viewedElements.has(element))
|
|
21
|
+
return;
|
|
22
|
+
const productId = element.getAttribute('data-raxon-product-id');
|
|
23
|
+
if (productId) {
|
|
24
|
+
viewedElements.add(element);
|
|
25
|
+
trackProductView({
|
|
26
|
+
productId,
|
|
27
|
+
variantId: element.getAttribute('data-raxon-variant-id'),
|
|
28
|
+
});
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (element instanceof HTMLAnchorElement) {
|
|
32
|
+
const hrefProductId = extractProductIdFromHref(element.href, productPathPrefix);
|
|
33
|
+
if (hrefProductId) {
|
|
34
|
+
viewedElements.add(element);
|
|
35
|
+
trackProductView({ productId: hrefProductId });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const viewObserver = new IntersectionObserver((entries) => {
|
|
40
|
+
entries.forEach((entry) => {
|
|
41
|
+
if (entry.isIntersecting) {
|
|
42
|
+
trackVisibleElement(entry.target);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}, { threshold: 0.5 });
|
|
46
|
+
const observeCandidates = () => {
|
|
47
|
+
document
|
|
48
|
+
.querySelectorAll('[data-raxon-product-id], a[href]')
|
|
49
|
+
.forEach((element) => {
|
|
50
|
+
if (element.hasAttribute('data-raxon-product-id')) {
|
|
51
|
+
viewObserver.observe(element);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (element instanceof HTMLAnchorElement) {
|
|
55
|
+
const productId = extractProductIdFromHref(element.href, productPathPrefix);
|
|
56
|
+
if (productId) {
|
|
57
|
+
viewObserver.observe(element);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
const onClick = (event) => {
|
|
63
|
+
const target = event.target;
|
|
64
|
+
if (!(target instanceof Element))
|
|
65
|
+
return;
|
|
66
|
+
const productEvent = readProductFromElement(target, productPathPrefix);
|
|
67
|
+
if (productEvent) {
|
|
68
|
+
trackProductClick(productEvent);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const mutationObserver = new MutationObserver(observeCandidates);
|
|
72
|
+
document.addEventListener('click', onClick, true);
|
|
73
|
+
mutationObserver.observe(document.body, { childList: true, subtree: true });
|
|
74
|
+
observeCandidates();
|
|
75
|
+
return () => {
|
|
76
|
+
document.removeEventListener('click', onClick, true);
|
|
77
|
+
viewObserver.disconnect();
|
|
78
|
+
mutationObserver.disconnect();
|
|
79
|
+
};
|
|
80
|
+
}, [enabled, productPathPrefix, trackProductClick, trackProductView]);
|
|
81
|
+
}
|
|
@@ -37,10 +37,12 @@ export interface RaxonContextType extends RaxonBootstrapData, CartState {
|
|
|
37
37
|
isAuthenticated: boolean;
|
|
38
38
|
isGuest: boolean;
|
|
39
39
|
}
|
|
40
|
-
export declare const RaxonProvider: ({ children, apiKey, apiUrl, }: {
|
|
40
|
+
export declare const RaxonProvider: ({ children, apiKey, apiUrl, productPathPrefix, analyticAutoTrack, }: {
|
|
41
41
|
children: React.ReactNode;
|
|
42
42
|
apiKey: string;
|
|
43
43
|
apiUrl: string;
|
|
44
|
+
productPathPrefix?: string;
|
|
45
|
+
analyticAutoTrack?: boolean;
|
|
44
46
|
}) => import("react").JSX.Element;
|
|
45
47
|
export declare const useRaxon: () => RaxonContextType;
|
|
46
48
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"raxon.context.d.ts","sourceRoot":"","sources":["../../core/raxon.context.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,OAAO,EACP,WAAW,EACX,MAAM,EACN,KAAK,EACL,QAAQ,EAER,QAAQ,EACR,UAAU,EACV,cAAc,EACd,WAAW,EACX,GAAG,EACH,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,aAAa,EACb,MAAM,EACN,IAAI,EACL,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,EAAa,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAiC,gCAAgC,EAAE,MAAM,0DAA0D,CAAC;AAG3I,OAAO,EAAgB,SAAS,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"raxon.context.d.ts","sourceRoot":"","sources":["../../core/raxon.context.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,OAAO,EACP,WAAW,EACX,MAAM,EACN,KAAK,EACL,QAAQ,EAER,QAAQ,EACR,UAAU,EACV,cAAc,EACd,WAAW,EACX,GAAG,EACH,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,aAAa,EACb,MAAM,EACN,IAAI,EACL,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,EAAa,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAiC,gCAAgC,EAAE,MAAM,0DAA0D,CAAC;AAG3I,OAAO,EAAgB,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAGtE,eAAO,MAAM,YAAY,2CAAyD,CAAC;AAEnF,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,cAAc,EAAE,QAAQ,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,iBAAiB,EAAE,UAAU,EAAE,CAAC;IAChC,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,YAAY,EAAE,QAAQ,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,GAAG,EAAE,GAAG,EAAE,CAAC;IACX,IAAI,EAAE,IAAI,EAAE,CAAC;IACb,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,WAAW,EAAE,WAAW,EAAE,CAAC;IAC3B,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,WAAW,EAAE,WAAW,EAAE,CAAC;IAC3B,cAAc,EAAE,cAAc,EAAE,CAAC;IACjC,aAAa,EAAE,aAAa,EAAE,CAAC;IAC/B,qBAAqB,EAAE,cAAc,GAAG,IAAI,CAAC;IAC7C,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IACnD,gCAAgC,EAAE,KAAK,CAAC,SAAS,CAAC,gCAAgC,GAAG,IAAI,CAAC,CAAC;CAC5F;AAED,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB,EAAE,SAAS;IACrE,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB;AA0GD,eAAO,MAAM,aAAa,GAAI,qEAM3B;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,gCAeA,CAAC;AAEF,eAAO,MAAM,QAAQ,QAAO,gBAM3B,CAAC"}
|
|
@@ -8,23 +8,22 @@ import { ModalNewsletterVariantProduct } from './feature/newsletter/modal/modal.
|
|
|
8
8
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
9
9
|
import { useSecurityState } from './context/security.context';
|
|
10
10
|
import { useCartState } from './context/cart.context';
|
|
11
|
+
import { AnalyticEventProvider } from './feature/analytic-event/analytic.event.context';
|
|
11
12
|
export const RaxonContext = createContext(undefined);
|
|
12
|
-
const RaxonProviderInner = ({ children, apiKey, apiUrl, }) => {
|
|
13
|
+
const RaxonProviderInner = ({ children, apiKey, apiUrl, productPathPrefix, analyticAutoTrack, }) => {
|
|
13
14
|
const [raxon, setRaxon] = useState(null);
|
|
14
15
|
const [isLoading, setIsLoading] = useState(true);
|
|
15
16
|
const [hasFetched, setHasFetched] = useState(false);
|
|
16
17
|
const modalAuthRef = useRef(null);
|
|
17
18
|
const modalNewsletterVariantProductRef = useRef(null);
|
|
19
|
+
if (typeof window !== 'undefined') {
|
|
20
|
+
window.__RAXON_API_KEY__ = apiKey;
|
|
21
|
+
window.__RAXON_API_URL__ = apiUrl;
|
|
22
|
+
nexineAxios.defaults.baseURL = apiUrl;
|
|
23
|
+
nexineAxios.defaults.headers.common['x-api-key'] = apiKey;
|
|
24
|
+
}
|
|
18
25
|
const { profile, authLoading, isAuthenticated, isGuest } = useSecurityState();
|
|
19
26
|
const cartState = useCartState(isAuthenticated);
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
if (typeof window !== 'undefined') {
|
|
22
|
-
window.__RAXON_API_KEY__ = apiKey;
|
|
23
|
-
window.__RAXON_API_URL__ = apiUrl;
|
|
24
|
-
nexineAxios.defaults.baseURL = apiUrl;
|
|
25
|
-
nexineAxios.defaults.headers.common['x-api-key'] = apiKey;
|
|
26
|
-
}
|
|
27
|
-
}, [apiKey, apiUrl]);
|
|
28
27
|
useEffect(() => {
|
|
29
28
|
if (hasFetched || !apiUrl)
|
|
30
29
|
return;
|
|
@@ -82,11 +81,11 @@ const RaxonProviderInner = ({ children, apiKey, apiUrl, }) => {
|
|
|
82
81
|
isGuest,
|
|
83
82
|
...cartState,
|
|
84
83
|
}), [raxon, isLoading, flatCategory, profile, authLoading, isAuthenticated, isGuest, cartState]);
|
|
85
|
-
return (_jsxs(RaxonContext.Provider, { value: value, children: [children, _jsx(ModalAuth, { ref: modalAuthRef }), _jsx(ModalNewsletterVariantProduct, { ref: modalNewsletterVariantProductRef })] }));
|
|
84
|
+
return (_jsxs(RaxonContext.Provider, { value: value, children: [_jsx(AnalyticEventProvider, { productPathPrefix: productPathPrefix, autoTrack: analyticAutoTrack, children: children }), _jsx(ModalAuth, { ref: modalAuthRef }), _jsx(ModalNewsletterVariantProduct, { ref: modalNewsletterVariantProductRef })] }));
|
|
86
85
|
};
|
|
87
|
-
export const RaxonProvider = ({ children, apiKey, apiUrl, }) => {
|
|
86
|
+
export const RaxonProvider = ({ children, apiKey, apiUrl, productPathPrefix, analyticAutoTrack, }) => {
|
|
88
87
|
const [queryClient] = useState(() => new QueryClient());
|
|
89
|
-
return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(RaxonProviderInner, { apiKey: apiKey, apiUrl: apiUrl, children: children }) }));
|
|
88
|
+
return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(RaxonProviderInner, { apiKey: apiKey, apiUrl: apiUrl, productPathPrefix: productPathPrefix, analyticAutoTrack: analyticAutoTrack, children: children }) }));
|
|
90
89
|
};
|
|
91
90
|
export const useRaxon = () => {
|
|
92
91
|
const context = useContext(RaxonContext);
|
|
@@ -7,7 +7,29 @@ export const nexineAxios = axios.create({
|
|
|
7
7
|
'x-api-key': typeof window !== 'undefined' ? window.__RAXON_API_KEY__ : (process.env.NEXT_PUBLIC_API_KEY || ''),
|
|
8
8
|
},
|
|
9
9
|
});
|
|
10
|
+
const resolveApiKey = () => {
|
|
11
|
+
if (typeof window !== 'undefined') {
|
|
12
|
+
return (window.__RAXON_API_KEY__ ||
|
|
13
|
+
nexineAxios.defaults.headers.common['x-api-key'] ||
|
|
14
|
+
'');
|
|
15
|
+
}
|
|
16
|
+
return process.env.NEXT_PUBLIC_API_KEY || '';
|
|
17
|
+
};
|
|
18
|
+
const resolveApiUrl = () => {
|
|
19
|
+
if (typeof window !== 'undefined') {
|
|
20
|
+
return window.__RAXON_API_URL__ || nexineAxios.defaults.baseURL;
|
|
21
|
+
}
|
|
22
|
+
return process.env.NEXT_PUBLIC_API_URL;
|
|
23
|
+
};
|
|
10
24
|
nexineAxios.interceptors.request.use(config => {
|
|
25
|
+
const apiKey = resolveApiKey();
|
|
26
|
+
if (apiKey) {
|
|
27
|
+
config.headers['x-api-key'] = apiKey;
|
|
28
|
+
}
|
|
29
|
+
const apiUrl = resolveApiUrl();
|
|
30
|
+
if (apiUrl) {
|
|
31
|
+
config.baseURL = apiUrl;
|
|
32
|
+
}
|
|
11
33
|
if (typeof window !== 'undefined') {
|
|
12
34
|
const token = localStorage.getItem('koksal-token');
|
|
13
35
|
if (token) {
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
export
|
|
1
|
+
export interface CheckoutViewProps {
|
|
2
|
+
webReturnUrl?: string;
|
|
3
|
+
}
|
|
4
|
+
export default function PaymentPage({ webReturnUrl }: CheckoutViewProps): import("react").JSX.Element;
|
|
5
|
+
export { PaymentPage as CheckoutView };
|
|
2
6
|
//# sourceMappingURL=view.checkout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.checkout.d.ts","sourceRoot":"","sources":["../../../core/view/view.checkout.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"view.checkout.d.ts","sourceRoot":"","sources":["../../../core/view/view.checkout.tsx"],"names":[],"mappings":"AAyEA,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAs1DD,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAAE,YAA6B,EAAE,EAAE,iBAAiB,+BAQvF;AAED,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,CAAC"}
|