@uptrademedia/site-kit 1.0.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.
Files changed (120) hide show
  1. package/README.md +305 -0
  2. package/dist/analytics/index.js +88 -0
  3. package/dist/analytics/index.js.map +1 -0
  4. package/dist/analytics/index.mjs +70 -0
  5. package/dist/analytics/index.mjs.map +1 -0
  6. package/dist/api-N35S3EES.js +57 -0
  7. package/dist/api-N35S3EES.js.map +1 -0
  8. package/dist/api-SYBTK7Z7.mjs +4 -0
  9. package/dist/api-SYBTK7Z7.mjs.map +1 -0
  10. package/dist/blog/index.js +200 -0
  11. package/dist/blog/index.js.map +1 -0
  12. package/dist/blog/index.mjs +194 -0
  13. package/dist/blog/index.mjs.map +1 -0
  14. package/dist/chunk-3MUOUXHV.js +3721 -0
  15. package/dist/chunk-3MUOUXHV.js.map +1 -0
  16. package/dist/chunk-4HVYXYQL 2.mjs +255 -0
  17. package/dist/chunk-4HVYXYQL.mjs +255 -0
  18. package/dist/chunk-4HVYXYQL.mjs.map +1 -0
  19. package/dist/chunk-7H6I3ECV.mjs +120 -0
  20. package/dist/chunk-7H6I3ECV.mjs.map +1 -0
  21. package/dist/chunk-COI6GOX2.mjs +3679 -0
  22. package/dist/chunk-COI6GOX2.mjs.map +1 -0
  23. package/dist/chunk-EQCVQC35.js +35 -0
  24. package/dist/chunk-EQCVQC35.js 2.map +1 -0
  25. package/dist/chunk-EQCVQC35.js.map +1 -0
  26. package/dist/chunk-FEBYQGY4 2.mjs +251 -0
  27. package/dist/chunk-FEBYQGY4.mjs +251 -0
  28. package/dist/chunk-FEBYQGY4.mjs.map +1 -0
  29. package/dist/chunk-FKVJOT2F.mjs +796 -0
  30. package/dist/chunk-FKVJOT2F.mjs.map +1 -0
  31. package/dist/chunk-GQ6ZOU2N.mjs +134 -0
  32. package/dist/chunk-GQ6ZOU2N.mjs.map +1 -0
  33. package/dist/chunk-HCFPU7TU.js +137 -0
  34. package/dist/chunk-HCFPU7TU.js.map +1 -0
  35. package/dist/chunk-NYKRE2FL 2.mjs +31 -0
  36. package/dist/chunk-NYKRE2FL.mjs +31 -0
  37. package/dist/chunk-NYKRE2FL.mjs 2.map +1 -0
  38. package/dist/chunk-NYKRE2FL.mjs.map +1 -0
  39. package/dist/chunk-QP5NCO2E.js +133 -0
  40. package/dist/chunk-QP5NCO2E.js.map +1 -0
  41. package/dist/chunk-RV7H3I6J.js +255 -0
  42. package/dist/chunk-RV7H3I6J.js 2.map +1 -0
  43. package/dist/chunk-RV7H3I6J.js.map +1 -0
  44. package/dist/chunk-SBVEYCSV.js +140 -0
  45. package/dist/chunk-SBVEYCSV.js.map +1 -0
  46. package/dist/chunk-TUKGA3UK.js +257 -0
  47. package/dist/chunk-TUKGA3UK.js 2.map +1 -0
  48. package/dist/chunk-TUKGA3UK.js.map +1 -0
  49. package/dist/chunk-V3F5J6CV.js +801 -0
  50. package/dist/chunk-V3F5J6CV.js.map +1 -0
  51. package/dist/chunk-WPSRS352.mjs +135 -0
  52. package/dist/chunk-WPSRS352.mjs.map +1 -0
  53. package/dist/commerce/index.js +157 -0
  54. package/dist/commerce/index.js.map +1 -0
  55. package/dist/commerce/index.mjs +4 -0
  56. package/dist/commerce/index.mjs.map +1 -0
  57. package/dist/commerce/server.js +186 -0
  58. package/dist/commerce/server.js.map +1 -0
  59. package/dist/commerce/server.mjs +176 -0
  60. package/dist/commerce/server.mjs.map +1 -0
  61. package/dist/engage/index.js +50 -0
  62. package/dist/engage/index.js.map +1 -0
  63. package/dist/engage/index.mjs +44 -0
  64. package/dist/engage/index.mjs.map +1 -0
  65. package/dist/forms/index.js +1053 -0
  66. package/dist/forms/index.js.map +1 -0
  67. package/dist/forms/index.mjs +1035 -0
  68. package/dist/forms/index.mjs.map +1 -0
  69. package/dist/generators-7Y5ABRYV 2.mjs +161 -0
  70. package/dist/generators-7Y5ABRYV.mjs +161 -0
  71. package/dist/generators-7Y5ABRYV.mjs 2.map +1 -0
  72. package/dist/generators-7Y5ABRYV.mjs.map +1 -0
  73. package/dist/generators-GWIYCA5M.js +171 -0
  74. package/dist/generators-GWIYCA5M.js 2.map +1 -0
  75. package/dist/generators-GWIYCA5M.js.map +1 -0
  76. package/dist/index 2.mjs +74 -0
  77. package/dist/index.js +326 -0
  78. package/dist/index.js 2.map +1 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/index.mjs +222 -0
  81. package/dist/index.mjs.map +1 -0
  82. package/dist/migrator-V6KS75EA 2.mjs +265 -0
  83. package/dist/migrator-V6KS75EA.mjs +265 -0
  84. package/dist/migrator-V6KS75EA.mjs 2.map +1 -0
  85. package/dist/migrator-V6KS75EA.mjs.map +1 -0
  86. package/dist/migrator-XKM7YQCY.js +272 -0
  87. package/dist/migrator-XKM7YQCY.js 2.map +1 -0
  88. package/dist/migrator-XKM7YQCY.js.map +1 -0
  89. package/dist/scanner-MF7P3CDE 2.mjs +14386 -0
  90. package/dist/scanner-MF7P3CDE.mjs +14386 -0
  91. package/dist/scanner-MF7P3CDE.mjs 2.map +1 -0
  92. package/dist/scanner-MF7P3CDE.mjs.map +1 -0
  93. package/dist/scanner-NT6YG4TD 2.js +14397 -0
  94. package/dist/scanner-NT6YG4TD.js +14397 -0
  95. package/dist/scanner-NT6YG4TD.js 2.map +1 -0
  96. package/dist/scanner-NT6YG4TD.js.map +1 -0
  97. package/dist/seo/index.js +447 -0
  98. package/dist/seo/index.js.map +1 -0
  99. package/dist/seo/index.mjs +411 -0
  100. package/dist/seo/index.mjs.map +1 -0
  101. package/dist/seo/server.js +66 -0
  102. package/dist/seo/server.js.map +1 -0
  103. package/dist/seo/server.mjs +5 -0
  104. package/dist/seo/server.mjs.map +1 -0
  105. package/dist/setup/index.js +1050 -0
  106. package/dist/setup/index.js.map +1 -0
  107. package/dist/setup/index.mjs +1046 -0
  108. package/dist/setup/index.mjs.map +1 -0
  109. package/dist/sitemap/index.js +212 -0
  110. package/dist/sitemap/index.js.map +1 -0
  111. package/dist/sitemap/index.mjs +206 -0
  112. package/dist/sitemap/index.mjs.map +1 -0
  113. package/dist/web-vitals-BH55V7EJ.js +252 -0
  114. package/dist/web-vitals-BH55V7EJ.js 2.map +1 -0
  115. package/dist/web-vitals-BH55V7EJ.js.map +1 -0
  116. package/dist/web-vitals-RJYPWAR3 2.mjs +241 -0
  117. package/dist/web-vitals-RJYPWAR3.mjs +241 -0
  118. package/dist/web-vitals-RJYPWAR3.mjs 2.map +1 -0
  119. package/dist/web-vitals-RJYPWAR3.mjs.map +1 -0
  120. package/package.json +118 -0
@@ -0,0 +1,255 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import { usePathname } from 'next/navigation';
3
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
4
+
5
+ // src/engage/EngageWidget.tsx
6
+ function getApiConfig() {
7
+ const apiUrl = typeof window !== "undefined" ? window.__SITE_KIT_API_URL__ || "https://api.uptrademedia.com" : "https://api.uptrademedia.com";
8
+ const apiKey = typeof window !== "undefined" ? window.__SITE_KIT_API_KEY__ : void 0;
9
+ return { apiUrl, apiKey };
10
+ }
11
+ function EngageWidget({
12
+ apiUrl: propApiUrl,
13
+ apiKey: propApiKey,
14
+ position = "bottom-right",
15
+ zIndex = 9999,
16
+ chatEnabled = true,
17
+ debug = false
18
+ }) {
19
+ const pathname = usePathname();
20
+ const [elements, setElements] = useState([]);
21
+ const [activeElements, setActiveElements] = useState([]);
22
+ const [dismissedElements, setDismissedElements] = useState(/* @__PURE__ */ new Set());
23
+ useEffect(() => {
24
+ async function loadElements() {
25
+ const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig();
26
+ const apiUrl = propApiUrl || globalApiUrl;
27
+ const apiKey = propApiKey || globalApiKey;
28
+ if (!apiKey) {
29
+ if (debug) console.warn("[Engage] No API key configured");
30
+ return;
31
+ }
32
+ try {
33
+ const response = await fetch(`${apiUrl}/api/public/engage/elements`, {
34
+ method: "POST",
35
+ headers: {
36
+ "Content-Type": "application/json",
37
+ "x-api-key": apiKey
38
+ },
39
+ body: JSON.stringify({})
40
+ });
41
+ if (!response.ok) {
42
+ if (debug) console.error("[Engage] Error loading elements:", response.statusText);
43
+ return;
44
+ }
45
+ const data = await response.json();
46
+ if (debug) console.log("[Engage] Loaded elements:", data.elements);
47
+ setElements(data.elements || []);
48
+ } catch (error) {
49
+ if (debug) console.error("[Engage] Error loading elements:", error);
50
+ }
51
+ }
52
+ loadElements();
53
+ }, [propApiUrl, propApiKey, debug]);
54
+ useEffect(() => {
55
+ if (!elements.length) return;
56
+ const checkElement = (element) => {
57
+ if (dismissedElements.has(element.id)) return false;
58
+ if (element.targeting?.pages) {
59
+ const { include, exclude } = element.targeting.pages;
60
+ if (exclude?.some((p) => matchPath(pathname, p))) return false;
61
+ if (include && !include.some((p) => matchPath(pathname, p))) return false;
62
+ }
63
+ if (element.targeting?.devices) {
64
+ const device = getDeviceType();
65
+ if (!element.targeting.devices.includes(device)) return false;
66
+ }
67
+ if (element.trigger?.frequency) {
68
+ const { type, days } = element.trigger.frequency;
69
+ const key = `_engage_${element.id}`;
70
+ if (type === "once") {
71
+ if (localStorage.getItem(key)) return false;
72
+ } else if (type === "once-per-session") {
73
+ if (sessionStorage.getItem(key)) return false;
74
+ } else if (type === "every-n-days" && days) {
75
+ const lastShown = localStorage.getItem(key);
76
+ if (lastShown) {
77
+ const elapsed = Date.now() - parseInt(lastShown, 10);
78
+ if (elapsed < days * 24 * 60 * 60 * 1e3) return false;
79
+ }
80
+ }
81
+ }
82
+ return true;
83
+ };
84
+ const eligible = elements.filter(checkElement);
85
+ if (debug) console.log("[Engage] Eligible elements:", eligible);
86
+ eligible.forEach((element) => {
87
+ const trigger = element.trigger;
88
+ if (trigger?.type === "immediate" || !trigger?.type) {
89
+ setActiveElements((prev) => [...prev, element.id]);
90
+ } else if (trigger?.type === "delay" && trigger.delay) {
91
+ setTimeout(() => {
92
+ setActiveElements((prev) => [...prev, element.id]);
93
+ }, trigger.delay * 1e3);
94
+ } else if (trigger?.type === "exit-intent") {
95
+ const handleMouseLeave = (e) => {
96
+ if (e.clientY < 10) {
97
+ setActiveElements((prev) => [...prev, element.id]);
98
+ document.removeEventListener("mouseleave", handleMouseLeave);
99
+ }
100
+ };
101
+ document.addEventListener("mouseleave", handleMouseLeave);
102
+ } else if (trigger?.type === "scroll" && trigger.scrollPercent) {
103
+ const handleScroll = () => {
104
+ const scrollPercent = window.scrollY / (document.body.scrollHeight - window.innerHeight) * 100;
105
+ if (scrollPercent >= (trigger.scrollPercent || 50)) {
106
+ setActiveElements((prev) => [...prev, element.id]);
107
+ window.removeEventListener("scroll", handleScroll);
108
+ }
109
+ };
110
+ window.addEventListener("scroll", handleScroll);
111
+ }
112
+ });
113
+ }, [elements, pathname, dismissedElements, debug]);
114
+ const handleDismiss = useCallback((elementId) => {
115
+ setDismissedElements((prev) => /* @__PURE__ */ new Set([...prev, elementId]));
116
+ setActiveElements((prev) => prev.filter((id) => id !== elementId));
117
+ const element = elements.find((e) => e.id === elementId);
118
+ if (element?.trigger?.frequency) {
119
+ const key = `_engage_${elementId}`;
120
+ if (element.trigger.frequency.type === "once-per-session") {
121
+ sessionStorage.setItem(key, "true");
122
+ } else {
123
+ localStorage.setItem(key, Date.now().toString());
124
+ }
125
+ }
126
+ }, [elements]);
127
+ return /* @__PURE__ */ jsx(Fragment, { children: activeElements.map((elementId) => {
128
+ const element = elements.find((e) => e.id === elementId);
129
+ if (!element) return null;
130
+ return /* @__PURE__ */ jsx(
131
+ EngageElementRenderer,
132
+ {
133
+ element,
134
+ onDismiss: () => handleDismiss(element.id),
135
+ zIndex
136
+ },
137
+ element.id
138
+ );
139
+ }) });
140
+ }
141
+ function EngageElementRenderer({
142
+ element,
143
+ onDismiss,
144
+ zIndex
145
+ }) {
146
+ if (element.type === "popup") {
147
+ return /* @__PURE__ */ jsx(
148
+ "div",
149
+ {
150
+ style: {
151
+ position: "fixed",
152
+ top: 0,
153
+ left: 0,
154
+ right: 0,
155
+ bottom: 0,
156
+ backgroundColor: "rgba(0,0,0,0.5)",
157
+ display: "flex",
158
+ alignItems: "center",
159
+ justifyContent: "center",
160
+ zIndex
161
+ },
162
+ onClick: onDismiss,
163
+ children: /* @__PURE__ */ jsxs(
164
+ "div",
165
+ {
166
+ style: {
167
+ backgroundColor: "white",
168
+ padding: 24,
169
+ borderRadius: 8,
170
+ maxWidth: 500,
171
+ width: "90%"
172
+ },
173
+ onClick: (e) => e.stopPropagation(),
174
+ children: [
175
+ /* @__PURE__ */ jsx(
176
+ "button",
177
+ {
178
+ onClick: onDismiss,
179
+ style: {
180
+ position: "absolute",
181
+ top: 8,
182
+ right: 8,
183
+ background: "none",
184
+ border: "none",
185
+ fontSize: 24,
186
+ cursor: "pointer"
187
+ },
188
+ children: "\xD7"
189
+ }
190
+ ),
191
+ element.content?.title && /* @__PURE__ */ jsx("h2", { children: element.content.title }),
192
+ element.content?.body && /* @__PURE__ */ jsx("p", { children: element.content.body })
193
+ ]
194
+ }
195
+ )
196
+ }
197
+ );
198
+ }
199
+ if (element.type === "bar") {
200
+ return /* @__PURE__ */ jsxs(
201
+ "div",
202
+ {
203
+ style: {
204
+ position: "fixed",
205
+ top: 0,
206
+ left: 0,
207
+ right: 0,
208
+ backgroundColor: element.styles?.backgroundColor || "#3b82f6",
209
+ color: element.styles?.textColor || "white",
210
+ padding: "12px 24px",
211
+ display: "flex",
212
+ alignItems: "center",
213
+ justifyContent: "center",
214
+ gap: 16,
215
+ zIndex
216
+ },
217
+ children: [
218
+ /* @__PURE__ */ jsx("span", { children: element.content?.body }),
219
+ /* @__PURE__ */ jsx(
220
+ "button",
221
+ {
222
+ onClick: onDismiss,
223
+ style: {
224
+ background: "none",
225
+ border: "none",
226
+ color: "inherit",
227
+ fontSize: 20,
228
+ cursor: "pointer"
229
+ },
230
+ children: "\xD7"
231
+ }
232
+ )
233
+ ]
234
+ }
235
+ );
236
+ }
237
+ return null;
238
+ }
239
+ function matchPath(pathname, pattern) {
240
+ if (pattern.endsWith("*")) {
241
+ return pathname.startsWith(pattern.slice(0, -1));
242
+ }
243
+ return pathname === pattern;
244
+ }
245
+ function getDeviceType() {
246
+ if (typeof window === "undefined") return "desktop";
247
+ const ua = navigator.userAgent;
248
+ if (/tablet|ipad|playbook|silk/i.test(ua)) return "tablet";
249
+ if (/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(ua)) return "mobile";
250
+ return "desktop";
251
+ }
252
+
253
+ export { EngageWidget };
254
+ //# sourceMappingURL=chunk-4HVYXYQL.mjs.map
255
+ //# sourceMappingURL=chunk-4HVYXYQL.mjs.map
@@ -0,0 +1,255 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import { usePathname } from 'next/navigation';
3
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
4
+
5
+ // src/engage/EngageWidget.tsx
6
+ function getApiConfig() {
7
+ const apiUrl = typeof window !== "undefined" ? window.__SITE_KIT_API_URL__ || "https://api.uptrademedia.com" : "https://api.uptrademedia.com";
8
+ const apiKey = typeof window !== "undefined" ? window.__SITE_KIT_API_KEY__ : void 0;
9
+ return { apiUrl, apiKey };
10
+ }
11
+ function EngageWidget({
12
+ apiUrl: propApiUrl,
13
+ apiKey: propApiKey,
14
+ position = "bottom-right",
15
+ zIndex = 9999,
16
+ chatEnabled = true,
17
+ debug = false
18
+ }) {
19
+ const pathname = usePathname();
20
+ const [elements, setElements] = useState([]);
21
+ const [activeElements, setActiveElements] = useState([]);
22
+ const [dismissedElements, setDismissedElements] = useState(/* @__PURE__ */ new Set());
23
+ useEffect(() => {
24
+ async function loadElements() {
25
+ const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig();
26
+ const apiUrl = propApiUrl || globalApiUrl;
27
+ const apiKey = propApiKey || globalApiKey;
28
+ if (!apiKey) {
29
+ if (debug) console.warn("[Engage] No API key configured");
30
+ return;
31
+ }
32
+ try {
33
+ const response = await fetch(`${apiUrl}/api/public/engage/elements`, {
34
+ method: "POST",
35
+ headers: {
36
+ "Content-Type": "application/json",
37
+ "x-api-key": apiKey
38
+ },
39
+ body: JSON.stringify({})
40
+ });
41
+ if (!response.ok) {
42
+ if (debug) console.error("[Engage] Error loading elements:", response.statusText);
43
+ return;
44
+ }
45
+ const data = await response.json();
46
+ if (debug) console.log("[Engage] Loaded elements:", data.elements);
47
+ setElements(data.elements || []);
48
+ } catch (error) {
49
+ if (debug) console.error("[Engage] Error loading elements:", error);
50
+ }
51
+ }
52
+ loadElements();
53
+ }, [propApiUrl, propApiKey, debug]);
54
+ useEffect(() => {
55
+ if (!elements.length) return;
56
+ const checkElement = (element) => {
57
+ if (dismissedElements.has(element.id)) return false;
58
+ if (element.targeting?.pages) {
59
+ const { include, exclude } = element.targeting.pages;
60
+ if (exclude?.some((p) => matchPath(pathname, p))) return false;
61
+ if (include && !include.some((p) => matchPath(pathname, p))) return false;
62
+ }
63
+ if (element.targeting?.devices) {
64
+ const device = getDeviceType();
65
+ if (!element.targeting.devices.includes(device)) return false;
66
+ }
67
+ if (element.trigger?.frequency) {
68
+ const { type, days } = element.trigger.frequency;
69
+ const key = `_engage_${element.id}`;
70
+ if (type === "once") {
71
+ if (localStorage.getItem(key)) return false;
72
+ } else if (type === "once-per-session") {
73
+ if (sessionStorage.getItem(key)) return false;
74
+ } else if (type === "every-n-days" && days) {
75
+ const lastShown = localStorage.getItem(key);
76
+ if (lastShown) {
77
+ const elapsed = Date.now() - parseInt(lastShown, 10);
78
+ if (elapsed < days * 24 * 60 * 60 * 1e3) return false;
79
+ }
80
+ }
81
+ }
82
+ return true;
83
+ };
84
+ const eligible = elements.filter(checkElement);
85
+ if (debug) console.log("[Engage] Eligible elements:", eligible);
86
+ eligible.forEach((element) => {
87
+ const trigger = element.trigger;
88
+ if (trigger?.type === "immediate" || !trigger?.type) {
89
+ setActiveElements((prev) => [...prev, element.id]);
90
+ } else if (trigger?.type === "delay" && trigger.delay) {
91
+ setTimeout(() => {
92
+ setActiveElements((prev) => [...prev, element.id]);
93
+ }, trigger.delay * 1e3);
94
+ } else if (trigger?.type === "exit-intent") {
95
+ const handleMouseLeave = (e) => {
96
+ if (e.clientY < 10) {
97
+ setActiveElements((prev) => [...prev, element.id]);
98
+ document.removeEventListener("mouseleave", handleMouseLeave);
99
+ }
100
+ };
101
+ document.addEventListener("mouseleave", handleMouseLeave);
102
+ } else if (trigger?.type === "scroll" && trigger.scrollPercent) {
103
+ const handleScroll = () => {
104
+ const scrollPercent = window.scrollY / (document.body.scrollHeight - window.innerHeight) * 100;
105
+ if (scrollPercent >= (trigger.scrollPercent || 50)) {
106
+ setActiveElements((prev) => [...prev, element.id]);
107
+ window.removeEventListener("scroll", handleScroll);
108
+ }
109
+ };
110
+ window.addEventListener("scroll", handleScroll);
111
+ }
112
+ });
113
+ }, [elements, pathname, dismissedElements, debug]);
114
+ const handleDismiss = useCallback((elementId) => {
115
+ setDismissedElements((prev) => /* @__PURE__ */ new Set([...prev, elementId]));
116
+ setActiveElements((prev) => prev.filter((id) => id !== elementId));
117
+ const element = elements.find((e) => e.id === elementId);
118
+ if (element?.trigger?.frequency) {
119
+ const key = `_engage_${elementId}`;
120
+ if (element.trigger.frequency.type === "once-per-session") {
121
+ sessionStorage.setItem(key, "true");
122
+ } else {
123
+ localStorage.setItem(key, Date.now().toString());
124
+ }
125
+ }
126
+ }, [elements]);
127
+ return /* @__PURE__ */ jsx(Fragment, { children: activeElements.map((elementId) => {
128
+ const element = elements.find((e) => e.id === elementId);
129
+ if (!element) return null;
130
+ return /* @__PURE__ */ jsx(
131
+ EngageElementRenderer,
132
+ {
133
+ element,
134
+ onDismiss: () => handleDismiss(element.id),
135
+ zIndex
136
+ },
137
+ element.id
138
+ );
139
+ }) });
140
+ }
141
+ function EngageElementRenderer({
142
+ element,
143
+ onDismiss,
144
+ zIndex
145
+ }) {
146
+ if (element.type === "popup") {
147
+ return /* @__PURE__ */ jsx(
148
+ "div",
149
+ {
150
+ style: {
151
+ position: "fixed",
152
+ top: 0,
153
+ left: 0,
154
+ right: 0,
155
+ bottom: 0,
156
+ backgroundColor: "rgba(0,0,0,0.5)",
157
+ display: "flex",
158
+ alignItems: "center",
159
+ justifyContent: "center",
160
+ zIndex
161
+ },
162
+ onClick: onDismiss,
163
+ children: /* @__PURE__ */ jsxs(
164
+ "div",
165
+ {
166
+ style: {
167
+ backgroundColor: "white",
168
+ padding: 24,
169
+ borderRadius: 8,
170
+ maxWidth: 500,
171
+ width: "90%"
172
+ },
173
+ onClick: (e) => e.stopPropagation(),
174
+ children: [
175
+ /* @__PURE__ */ jsx(
176
+ "button",
177
+ {
178
+ onClick: onDismiss,
179
+ style: {
180
+ position: "absolute",
181
+ top: 8,
182
+ right: 8,
183
+ background: "none",
184
+ border: "none",
185
+ fontSize: 24,
186
+ cursor: "pointer"
187
+ },
188
+ children: "\xD7"
189
+ }
190
+ ),
191
+ element.content?.title && /* @__PURE__ */ jsx("h2", { children: element.content.title }),
192
+ element.content?.body && /* @__PURE__ */ jsx("p", { children: element.content.body })
193
+ ]
194
+ }
195
+ )
196
+ }
197
+ );
198
+ }
199
+ if (element.type === "bar") {
200
+ return /* @__PURE__ */ jsxs(
201
+ "div",
202
+ {
203
+ style: {
204
+ position: "fixed",
205
+ top: 0,
206
+ left: 0,
207
+ right: 0,
208
+ backgroundColor: element.styles?.backgroundColor || "#3b82f6",
209
+ color: element.styles?.textColor || "white",
210
+ padding: "12px 24px",
211
+ display: "flex",
212
+ alignItems: "center",
213
+ justifyContent: "center",
214
+ gap: 16,
215
+ zIndex
216
+ },
217
+ children: [
218
+ /* @__PURE__ */ jsx("span", { children: element.content?.body }),
219
+ /* @__PURE__ */ jsx(
220
+ "button",
221
+ {
222
+ onClick: onDismiss,
223
+ style: {
224
+ background: "none",
225
+ border: "none",
226
+ color: "inherit",
227
+ fontSize: 20,
228
+ cursor: "pointer"
229
+ },
230
+ children: "\xD7"
231
+ }
232
+ )
233
+ ]
234
+ }
235
+ );
236
+ }
237
+ return null;
238
+ }
239
+ function matchPath(pathname, pattern) {
240
+ if (pattern.endsWith("*")) {
241
+ return pathname.startsWith(pattern.slice(0, -1));
242
+ }
243
+ return pathname === pattern;
244
+ }
245
+ function getDeviceType() {
246
+ if (typeof window === "undefined") return "desktop";
247
+ const ua = navigator.userAgent;
248
+ if (/tablet|ipad|playbook|silk/i.test(ua)) return "tablet";
249
+ if (/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(ua)) return "mobile";
250
+ return "desktop";
251
+ }
252
+
253
+ export { EngageWidget };
254
+ //# sourceMappingURL=chunk-4HVYXYQL.mjs.map
255
+ //# sourceMappingURL=chunk-4HVYXYQL.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/engage/EngageWidget.tsx"],"names":[],"mappings":"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","file":"chunk-4HVYXYQL.mjs","sourcesContent":["/**\n * @uptrade/site-kit/engage - Engage Widget\n * \n * Loads and renders engagement widgets (popups, nudges, bars) via Portal API\n */\n\n'use client'\n\nimport React, { useEffect, useState, useCallback } from 'react'\nimport { usePathname } from 'next/navigation'\nimport type { EngageElement } from './types'\n\ninterface EngageWidgetProps {\n apiUrl?: string\n apiKey?: string\n position?: 'bottom-right' | 'bottom-left'\n zIndex?: number\n chatEnabled?: boolean\n debug?: boolean\n}\n\nfunction getApiConfig() {\n const apiUrl = typeof window !== 'undefined' \n ? (window as any).__SITE_KIT_API_URL__ || 'https://api.uptrademedia.com'\n : 'https://api.uptrademedia.com'\n const apiKey = typeof window !== 'undefined' \n ? (window as any).__SITE_KIT_API_KEY__\n : undefined\n return { apiUrl, apiKey }\n}\n\nexport function EngageWidget({\n apiUrl: propApiUrl,\n apiKey: propApiKey,\n position = 'bottom-right',\n zIndex = 9999,\n chatEnabled = true,\n debug = false,\n}: EngageWidgetProps) {\n const pathname = usePathname()\n const [elements, setElements] = useState<EngageElement[]>([])\n const [activeElements, setActiveElements] = useState<string[]>([])\n const [dismissedElements, setDismissedElements] = useState<Set<string>>(new Set())\n \n // Load elements from API\n useEffect(() => {\n async function loadElements() {\n const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig()\n const apiUrl = propApiUrl || globalApiUrl\n const apiKey = propApiKey || globalApiKey\n \n if (!apiKey) {\n if (debug) console.warn('[Engage] No API key configured')\n return\n }\n \n try {\n const response = await fetch(`${apiUrl}/api/public/engage/elements`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify({}),\n })\n \n if (!response.ok) {\n if (debug) console.error('[Engage] Error loading elements:', response.statusText)\n return\n }\n \n const data = await response.json()\n if (debug) console.log('[Engage] Loaded elements:', data.elements)\n setElements(data.elements || [])\n } catch (error) {\n if (debug) console.error('[Engage] Error loading elements:', error)\n }\n }\n \n loadElements()\n }, [propApiUrl, propApiKey, debug])\n \n // Check targeting and trigger for each element\n useEffect(() => {\n if (!elements.length) return\n \n const checkElement = (element: EngageElement): boolean => {\n // Check if dismissed\n if (dismissedElements.has(element.id)) return false\n \n // Check page targeting\n if (element.targeting?.pages) {\n const { include, exclude } = element.targeting.pages\n \n if (exclude?.some(p => matchPath(pathname, p))) return false\n if (include && !include.some(p => matchPath(pathname, p))) return false\n }\n \n // Check device targeting\n if (element.targeting?.devices) {\n const device = getDeviceType()\n if (!element.targeting.devices.includes(device)) return false\n }\n \n // Check frequency capping\n if (element.trigger?.frequency) {\n const { type, days } = element.trigger.frequency\n const key = `_engage_${element.id}`\n \n if (type === 'once') {\n if (localStorage.getItem(key)) return false\n } else if (type === 'once-per-session') {\n if (sessionStorage.getItem(key)) return false\n } else if (type === 'every-n-days' && days) {\n const lastShown = localStorage.getItem(key)\n if (lastShown) {\n const elapsed = Date.now() - parseInt(lastShown, 10)\n if (elapsed < days * 24 * 60 * 60 * 1000) return false\n }\n }\n }\n \n return true\n }\n \n // Filter elements that pass targeting\n const eligible = elements.filter(checkElement)\n \n if (debug) console.log('[Engage] Eligible elements:', eligible)\n \n // Set up triggers for eligible elements\n eligible.forEach(element => {\n const trigger = element.trigger\n \n if (trigger?.type === 'immediate' || !trigger?.type) {\n setActiveElements(prev => [...prev, element.id])\n } else if (trigger?.type === 'delay' && trigger.delay) {\n setTimeout(() => {\n setActiveElements(prev => [...prev, element.id])\n }, trigger.delay * 1000)\n } else if (trigger?.type === 'exit-intent') {\n const handleMouseLeave = (e: MouseEvent) => {\n if (e.clientY < 10) {\n setActiveElements(prev => [...prev, element.id])\n document.removeEventListener('mouseleave', handleMouseLeave)\n }\n }\n document.addEventListener('mouseleave', handleMouseLeave)\n } else if (trigger?.type === 'scroll' && trigger.scrollPercent) {\n const handleScroll = () => {\n const scrollPercent = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100\n if (scrollPercent >= (trigger.scrollPercent || 50)) {\n setActiveElements(prev => [...prev, element.id])\n window.removeEventListener('scroll', handleScroll)\n }\n }\n window.addEventListener('scroll', handleScroll)\n }\n })\n }, [elements, pathname, dismissedElements, debug])\n \n const handleDismiss = useCallback((elementId: string) => {\n setDismissedElements(prev => new Set([...prev, elementId]))\n setActiveElements(prev => prev.filter(id => id !== elementId))\n \n // Record dismissal in storage\n const element = elements.find(e => e.id === elementId)\n if (element?.trigger?.frequency) {\n const key = `_engage_${elementId}`\n if (element.trigger.frequency.type === 'once-per-session') {\n sessionStorage.setItem(key, 'true')\n } else {\n localStorage.setItem(key, Date.now().toString())\n }\n }\n }, [elements])\n \n // Render active elements\n return (\n <>\n {activeElements.map(elementId => {\n const element = elements.find(e => e.id === elementId)\n if (!element) return null\n \n return (\n <EngageElementRenderer\n key={element.id}\n element={element}\n onDismiss={() => handleDismiss(element.id)}\n zIndex={zIndex}\n />\n )\n })}\n </>\n )\n}\n\n// Helper components\nfunction EngageElementRenderer({ \n element, \n onDismiss,\n zIndex,\n}: { \n element: EngageElement\n onDismiss: () => void\n zIndex: number\n}) {\n // Simple popup rendering - expand as needed\n if (element.type === 'popup') {\n return (\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0,0,0,0.5)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex,\n }}\n onClick={onDismiss}\n >\n <div\n style={{\n backgroundColor: 'white',\n padding: 24,\n borderRadius: 8,\n maxWidth: 500,\n width: '90%',\n }}\n onClick={e => e.stopPropagation()}\n >\n <button\n onClick={onDismiss}\n style={{\n position: 'absolute',\n top: 8,\n right: 8,\n background: 'none',\n border: 'none',\n fontSize: 24,\n cursor: 'pointer',\n }}\n >\n ×\n </button>\n {element.content?.title && <h2>{element.content.title}</h2>}\n {element.content?.body && <p>{element.content.body}</p>}\n </div>\n </div>\n )\n }\n \n // Bar/banner rendering\n if (element.type === 'bar') {\n return (\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n backgroundColor: element.styles?.backgroundColor || '#3b82f6',\n color: element.styles?.textColor || 'white',\n padding: '12px 24px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 16,\n zIndex,\n }}\n >\n <span>{element.content?.body}</span>\n <button\n onClick={onDismiss}\n style={{\n background: 'none',\n border: 'none',\n color: 'inherit',\n fontSize: 20,\n cursor: 'pointer',\n }}\n >\n ×\n </button>\n </div>\n )\n }\n \n return null\n}\n\n// Utilities\nfunction matchPath(pathname: string, pattern: string): boolean {\n if (pattern.endsWith('*')) {\n return pathname.startsWith(pattern.slice(0, -1))\n }\n return pathname === pattern\n}\n\nfunction getDeviceType(): 'desktop' | 'mobile' | 'tablet' {\n if (typeof window === 'undefined') return 'desktop'\n const ua = navigator.userAgent\n if (/tablet|ipad|playbook|silk/i.test(ua)) return 'tablet'\n if (/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(ua)) return 'mobile'\n return 'desktop'\n}\n"]}
@@ -0,0 +1,120 @@
1
+ import { cache } from 'react';
2
+
3
+ // src/seo/api.ts
4
+ function getApiConfig() {
5
+ const apiUrl = process.env.NEXT_PUBLIC_UPTRADE_API_URL || "https://api.uptrademedia.com";
6
+ const apiKey = process.env.NEXT_PUBLIC_UPTRADE_API_KEY || "";
7
+ return { apiUrl, apiKey };
8
+ }
9
+ async function apiPost(endpoint, body = {}) {
10
+ const { apiUrl, apiKey } = getApiConfig();
11
+ if (!apiKey) {
12
+ console.error("@uptrade/seo: No API key configured. Set NEXT_PUBLIC_UPTRADE_API_KEY.");
13
+ return null;
14
+ }
15
+ try {
16
+ const response = await fetch(`${apiUrl}${endpoint}`, {
17
+ method: "POST",
18
+ headers: {
19
+ "Content-Type": "application/json",
20
+ "x-api-key": apiKey
21
+ },
22
+ body: JSON.stringify(body),
23
+ next: { revalidate: 60 }
24
+ // Cache for 60 seconds
25
+ });
26
+ if (!response.ok) {
27
+ console.error(`@uptrade/seo: API error: ${response.statusText}`);
28
+ return null;
29
+ }
30
+ return await response.json();
31
+ } catch (error) {
32
+ console.error("@uptrade/seo: Network error:", error);
33
+ return null;
34
+ }
35
+ }
36
+ var getSEOPageData = cache(async (projectId, path) => {
37
+ const result = await apiPost("/api/public/seo/page", { path });
38
+ return result?.page || null;
39
+ });
40
+ var getSchemaMarkups = cache(async (projectId, path, options) => {
41
+ const result = await apiPost("/api/public/seo/schemas", {
42
+ path,
43
+ includeTypes: options?.includeTypes,
44
+ excludeTypes: options?.excludeTypes
45
+ });
46
+ return result?.schemas || [];
47
+ });
48
+ var getFAQData = cache(async (projectId, path) => {
49
+ const result = await apiPost("/api/public/seo/faq", { path });
50
+ return result?.faq || null;
51
+ });
52
+ var getInternalLinks = cache(async (projectId, sourcePath, options) => {
53
+ const result = await apiPost("/api/public/seo/internal-links", {
54
+ sourcePath,
55
+ position: options?.position,
56
+ limit: options?.limit
57
+ });
58
+ return result?.links || [];
59
+ });
60
+ var getContentBlock = cache(async (projectId, path, section) => {
61
+ const result = await apiPost("/api/public/seo/content", { path, section });
62
+ return result?.content || null;
63
+ });
64
+ var getABTest = cache(async (projectId, path, field) => {
65
+ const result = await apiPost("/api/public/seo/ab-test", { path, field });
66
+ return result?.test || null;
67
+ });
68
+ async function recordABImpression(testId, variant, sessionId) {
69
+ await apiPost("/api/public/seo/ab-impression", { testId, variant, sessionId });
70
+ }
71
+ var getRedirectData = cache(async (projectId, path) => {
72
+ const result = await apiPost("/api/public/seo/redirect", { path });
73
+ return result?.redirect || null;
74
+ });
75
+ var getManagedScripts = cache(async (projectId, position, currentPath) => {
76
+ const result = await apiPost("/api/public/seo/scripts", {
77
+ position,
78
+ currentPath
79
+ });
80
+ return result?.scripts || [];
81
+ });
82
+ var getRobotsData = cache(async (projectId, path) => {
83
+ const result = await apiPost("/api/public/seo/page", { path });
84
+ return result?.page?.managed_robots || null;
85
+ });
86
+ var getSitemapEntries = cache(async (projectId, options) => {
87
+ const result = await apiPost("/api/public/seo/sitemap", {
88
+ publishedOnly: options?.publishedOnly
89
+ });
90
+ return result?.entries || [];
91
+ });
92
+ async function registerSitemap(entries) {
93
+ const { apiUrl, apiKey } = getApiConfig();
94
+ if (!apiKey) {
95
+ console.error("@uptrade/seo: No API key configured. Set NEXT_PUBLIC_UPTRADE_API_KEY.");
96
+ return { success: false, created: 0, updated: 0 };
97
+ }
98
+ try {
99
+ const response = await fetch(`${apiUrl}/api/public/seo/register-sitemap`, {
100
+ method: "POST",
101
+ headers: {
102
+ "Content-Type": "application/json",
103
+ "x-api-key": apiKey
104
+ },
105
+ body: JSON.stringify({ entries })
106
+ });
107
+ if (!response.ok) {
108
+ console.error(`@uptrade/seo: Sitemap registration failed: ${response.statusText}`);
109
+ return { success: false, created: 0, updated: 0 };
110
+ }
111
+ return await response.json();
112
+ } catch (error) {
113
+ console.error("@uptrade/seo: Sitemap registration error:", error);
114
+ return { success: false, created: 0, updated: 0 };
115
+ }
116
+ }
117
+
118
+ export { getABTest, getContentBlock, getFAQData, getInternalLinks, getManagedScripts, getRedirectData, getRobotsData, getSEOPageData, getSchemaMarkups, getSitemapEntries, recordABImpression, registerSitemap };
119
+ //# sourceMappingURL=chunk-7H6I3ECV.mjs.map
120
+ //# sourceMappingURL=chunk-7H6I3ECV.mjs.map