@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
package/README.md ADDED
@@ -0,0 +1,305 @@
1
+ # @uptrade/site-kit
2
+
3
+ Complete client-side integration kit for Uptrade Portal. One package for SEO, Analytics, Engage widgets, Forms, and Blog - all managed from your Uptrade Portal dashboard.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @uptrade/site-kit
9
+ # or
10
+ pnpm add @uptrade/site-kit
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ Wrap your app with `SiteKitProvider` in your root layout:
16
+
17
+ ```tsx
18
+ // app/layout.tsx
19
+ import { SiteKitProvider } from '@uptrade/site-kit'
20
+
21
+ export default function RootLayout({ children }) {
22
+ return (
23
+ <html>
24
+ <body>
25
+ <SiteKitProvider
26
+ projectId={process.env.UPTRADE_PROJECT_ID!}
27
+ supabaseUrl={process.env.NEXT_PUBLIC_SUPABASE_URL!}
28
+ supabaseAnonKey={process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!}
29
+ analytics={{ enabled: true }}
30
+ engage={{ enabled: true }}
31
+ >
32
+ {children}
33
+ </SiteKitProvider>
34
+ </body>
35
+ </html>
36
+ )
37
+ }
38
+ ```
39
+
40
+ ## Modules
41
+
42
+ ### SEO (`@uptrade/site-kit/seo`)
43
+
44
+ Managed SEO components that automatically inject structured data, FAQs, internal links, and more based on your Portal configuration.
45
+
46
+ ```tsx
47
+ import { ManagedSchema, ManagedFAQ, ManagedInternalLinks } from '@uptrade/site-kit/seo'
48
+ import { getManagedMetadata, generateSitemap, generateRobots } from '@uptrade/site-kit/seo/server'
49
+
50
+ // In a page component
51
+ export async function generateMetadata({ params }) {
52
+ return getManagedMetadata('your-project-id', `/blog/${params.slug}`)
53
+ }
54
+
55
+ export default async function BlogPost({ params }) {
56
+ return (
57
+ <article>
58
+ <h1>My Blog Post</h1>
59
+ <p>Content...</p>
60
+
61
+ {/* Managed structured data */}
62
+ <ManagedSchema projectId="..." path="/blog/my-post" />
63
+
64
+ {/* Managed FAQ section */}
65
+ <ManagedFAQ projectId="..." path="/blog/my-post" />
66
+
67
+ {/* Managed internal links */}
68
+ <ManagedInternalLinks projectId="..." path="/blog/my-post" />
69
+ </article>
70
+ )
71
+ }
72
+ ```
73
+
74
+ ### Analytics (`@uptrade/site-kit/analytics`)
75
+
76
+ Automatic page view tracking, custom events, and Core Web Vitals reporting.
77
+
78
+ ```tsx
79
+ import { useAnalytics, WebVitals } from '@uptrade/site-kit/analytics'
80
+
81
+ export default function MyComponent() {
82
+ const { trackEvent, trackConversion } = useAnalytics()
83
+
84
+ const handleClick = () => {
85
+ trackEvent('button_click', { button: 'cta' })
86
+ }
87
+
88
+ const handlePurchase = () => {
89
+ trackConversion('purchase', 99.99)
90
+ }
91
+
92
+ return (
93
+ <>
94
+ <button onClick={handleClick}>CTA Button</button>
95
+ <WebVitals /> {/* Reports LCP, CLS, FID, etc. */}
96
+ </>
97
+ )
98
+ }
99
+ ```
100
+
101
+ ### Engage (`@uptrade/site-kit/engage`)
102
+
103
+ Popups, nudges, banners, and chat widgets configured from Portal.
104
+
105
+ ```tsx
106
+ import { EngageWidget, ChatWidget } from '@uptrade/site-kit/engage'
107
+
108
+ // Automatically included when engage.enabled = true in SiteKitProvider
109
+ // Or add manually:
110
+
111
+ export default function Layout({ children }) {
112
+ return (
113
+ <>
114
+ {children}
115
+ <EngageWidget projectId="..." />
116
+ <ChatWidget projectId="..." />
117
+ </>
118
+ )
119
+ }
120
+ ```
121
+
122
+ ### Forms (`@uptrade/site-kit/forms`)
123
+
124
+ Managed forms with automatic routing to CRM, Support, or other destinations.
125
+
126
+ ```tsx
127
+ import { ManagedForm } from '@uptrade/site-kit/forms'
128
+
129
+ // Basic usage - fetches form config from Portal
130
+ export default function ContactPage() {
131
+ return (
132
+ <ManagedForm
133
+ projectId="..."
134
+ formSlug="contact-form"
135
+ onSuccess={(data) => console.log('Submitted:', data)}
136
+ />
137
+ )
138
+ }
139
+
140
+ // Custom rendering
141
+ export default function CustomContactPage() {
142
+ return (
143
+ <ManagedForm
144
+ projectId="..."
145
+ formSlug="contact-form"
146
+ render={({ fields, step, totalSteps, values, errors, handleSubmit, isSubmitting }) => (
147
+ <form onSubmit={handleSubmit}>
148
+ {fields.map(field => (
149
+ <CustomField key={field.slug} {...field} />
150
+ ))}
151
+ <button disabled={isSubmitting}>Submit</button>
152
+ </form>
153
+ )}
154
+ />
155
+ )
156
+ }
157
+ ```
158
+
159
+ ### Blog (`@uptrade/site-kit/blog`)
160
+
161
+ Blog components with built-in SEO and related post suggestions.
162
+
163
+ ```tsx
164
+ import { BlogPost, BlogList, RelatedPosts, TableOfContents, AuthorCard } from '@uptrade/site-kit/blog'
165
+
166
+ // Blog listing page
167
+ export default function BlogPage() {
168
+ return (
169
+ <BlogList
170
+ projectId="..."
171
+ options={{
172
+ limit: 10,
173
+ category: 'news',
174
+ orderBy: 'published_at',
175
+ order: 'desc'
176
+ }}
177
+ />
178
+ )
179
+ }
180
+
181
+ // Blog post page
182
+ export default function BlogPostPage({ params }) {
183
+ return (
184
+ <div className="flex">
185
+ <aside className="w-64">
186
+ <TableOfContents content={post.content_html} />
187
+ </aside>
188
+ <main>
189
+ <BlogPost projectId="..." slug={params.slug} />
190
+ <AuthorCard author={post.author} />
191
+ <RelatedPosts projectId="..." currentPostId={post.id} limit={3} />
192
+ </main>
193
+ </div>
194
+ )
195
+ }
196
+ ```
197
+
198
+ ## Configuration
199
+
200
+ ### Full Provider Options
201
+
202
+ ```tsx
203
+ <SiteKitProvider
204
+ // Required
205
+ projectId="your-project-id"
206
+ supabaseUrl="https://xxx.supabase.co"
207
+ supabaseAnonKey="your-anon-key"
208
+
209
+ // Analytics options
210
+ analytics={{
211
+ enabled: true,
212
+ trackPageViews: true, // Auto-track route changes
213
+ trackWebVitals: true, // Report Core Web Vitals
214
+ trackScrollDepth: false, // Track scroll milestones
215
+ sessionDuration: 30, // Session timeout in minutes
216
+ excludePaths: ['/admin'] // Don't track these paths
217
+ }}
218
+
219
+ // Engage widget options
220
+ engage={{
221
+ enabled: true,
222
+ position: 'bottom-right', // Widget position
223
+ zIndex: 9999,
224
+ chatEnabled: true // Enable AI/live chat
225
+ }}
226
+
227
+ // Forms options
228
+ forms={{
229
+ enabled: true,
230
+ honeypotField: '_hp' // Spam protection field name
231
+ }}
232
+
233
+ // Debug mode - logs to console
234
+ debug={false}
235
+ >
236
+ ```
237
+
238
+ ## Environment Variables
239
+
240
+ ```bash
241
+ # Required
242
+ UPTRADE_PROJECT_ID=your-project-id
243
+ NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
244
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
245
+ ```
246
+
247
+ ## Server-Side Utilities
248
+
249
+ ```tsx
250
+ // app/sitemap.ts
251
+ import { generateSitemap } from '@uptrade/site-kit/seo/server'
252
+
253
+ export default async function sitemap() {
254
+ return generateSitemap('your-project-id', 'https://yoursite.com')
255
+ }
256
+
257
+ // app/robots.ts
258
+ import { generateRobots } from '@uptrade/site-kit/seo/server'
259
+
260
+ export default async function robots() {
261
+ return generateRobots('your-project-id', 'https://yoursite.com')
262
+ }
263
+
264
+ // Redirect handling in middleware
265
+ import { handleRedirect } from '@uptrade/site-kit/seo/server'
266
+
267
+ export async function middleware(request) {
268
+ const redirect = await handleRedirect('your-project-id', request.nextUrl.pathname)
269
+ if (redirect) {
270
+ return NextResponse.redirect(new URL(redirect.to, request.url), redirect.statusCode)
271
+ }
272
+ }
273
+ ```
274
+
275
+ ## Form Routing
276
+
277
+ Forms automatically route submissions based on their type:
278
+
279
+ | Form Type | Routes To | Use Case |
280
+ |-----------|-----------|----------|
281
+ | `prospect` | CRM Leads | Sales inquiries, quote requests |
282
+ | `support` | Support Tickets | Help requests, bug reports |
283
+ | `feedback` | Feedback Entries | User feedback, suggestions |
284
+ | `newsletter` | Email Subscribers | Newsletter signups |
285
+ | `contact` | Form Submissions | General contact (no routing) |
286
+ | `custom` | Form Submissions | Custom handling |
287
+
288
+ ## TypeScript
289
+
290
+ All modules are fully typed:
291
+
292
+ ```tsx
293
+ import type {
294
+ SiteKitConfig,
295
+ ManagedMetadata,
296
+ AnalyticsEvent,
297
+ EngageElement,
298
+ ManagedFormConfig,
299
+ BlogPostType
300
+ } from '@uptrade/site-kit'
301
+ ```
302
+
303
+ ## License
304
+
305
+ MIT
@@ -0,0 +1,88 @@
1
+ 'use strict';
2
+
3
+ var chunkV3F5J6CV_js = require('../chunk-V3F5J6CV.js');
4
+ require('../chunk-EQCVQC35.js');
5
+ var react = require('react');
6
+
7
+ function useContactTracking(options = {}) {
8
+ const { autoTrack = true, debug = false } = options;
9
+ const { trackConversion } = chunkV3F5J6CV_js.useAnalytics();
10
+ const trackPhoneClick = react.useCallback((phoneNumber, metadata) => {
11
+ if (debug) console.log("[Analytics] Phone click:", phoneNumber);
12
+ trackConversion({
13
+ type: "phone_call",
14
+ metadata: {
15
+ phoneNumber: phoneNumber.replace(/\D/g, ""),
16
+ // Normalize to digits
17
+ rawNumber: phoneNumber,
18
+ ...metadata
19
+ }
20
+ });
21
+ }, [trackConversion, debug]);
22
+ const trackEmailClick = react.useCallback((email, metadata) => {
23
+ if (debug) console.log("[Analytics] Email click:", email);
24
+ trackConversion({
25
+ type: "email_click",
26
+ metadata: {
27
+ email,
28
+ ...metadata
29
+ }
30
+ });
31
+ }, [trackConversion, debug]);
32
+ react.useEffect(() => {
33
+ if (!autoTrack || typeof document === "undefined") return;
34
+ const handleClick = (e) => {
35
+ const target = e.target;
36
+ const anchor = target.closest("a");
37
+ if (!anchor) return;
38
+ const href = anchor.getAttribute("href");
39
+ if (!href) return;
40
+ if (href.startsWith("tel:")) {
41
+ const phone = href.replace("tel:", "").trim();
42
+ trackPhoneClick(phone, {
43
+ linkText: anchor.textContent?.trim(),
44
+ source: "auto"
45
+ });
46
+ } else if (href.startsWith("mailto:")) {
47
+ const email = href.replace("mailto:", "").split("?")[0].trim();
48
+ trackEmailClick(email, {
49
+ linkText: anchor.textContent?.trim(),
50
+ source: "auto"
51
+ });
52
+ }
53
+ };
54
+ document.addEventListener("click", handleClick, { capture: true });
55
+ return () => {
56
+ document.removeEventListener("click", handleClick, { capture: true });
57
+ };
58
+ }, [autoTrack, trackPhoneClick, trackEmailClick]);
59
+ return {
60
+ trackPhoneClick,
61
+ trackEmailClick
62
+ };
63
+ }
64
+ function ContactTracking({ debug = false }) {
65
+ useContactTracking({ autoTrack: true, debug });
66
+ return null;
67
+ }
68
+
69
+ Object.defineProperty(exports, "AnalyticsProvider", {
70
+ enumerable: true,
71
+ get: function () { return chunkV3F5J6CV_js.AnalyticsProvider; }
72
+ });
73
+ Object.defineProperty(exports, "WebVitals", {
74
+ enumerable: true,
75
+ get: function () { return chunkV3F5J6CV_js.WebVitals; }
76
+ });
77
+ Object.defineProperty(exports, "useAnalytics", {
78
+ enumerable: true,
79
+ get: function () { return chunkV3F5J6CV_js.useAnalytics; }
80
+ });
81
+ Object.defineProperty(exports, "useTrackEvent", {
82
+ enumerable: true,
83
+ get: function () { return chunkV3F5J6CV_js.useTrackEvent; }
84
+ });
85
+ exports.ContactTracking = ContactTracking;
86
+ exports.useContactTracking = useContactTracking;
87
+ //# sourceMappingURL=index.js.map
88
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/analytics/useContactTracking.ts"],"names":["useAnalytics","useCallback","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @uptrade/site-kit/analytics - Contact Tracking Hook\n * \n * Tracks phone calls and email clicks as conversions.\n * Use this hook to automatically track tel: and mailto: links,\n * or manually track contact interactions.\n */\n\n'use client'\n\nimport { useCallback, useEffect } from 'react'\nimport { useAnalytics } from './AnalyticsProvider'\n\nexport interface UseContactTrackingOptions {\n /** Automatically track all tel: and mailto: links (default: true) */\n autoTrack?: boolean\n /** Debug mode - logs events to console */\n debug?: boolean\n}\n\nexport interface ContactTrackingReturn {\n /** Manually track a phone call click */\n trackPhoneClick: (phoneNumber: string, metadata?: Record<string, unknown>) => void\n /** Manually track an email click */\n trackEmailClick: (email: string, metadata?: Record<string, unknown>) => void\n}\n\n/**\n * Hook for tracking phone and email contact interactions as conversions.\n * \n * @example\n * ```tsx\n * // Auto-track all tel: and mailto: links\n * useContactTracking()\n * \n * // Manual tracking\n * const { trackPhoneClick, trackEmailClick } = useContactTracking()\n * trackPhoneClick('513-555-1234')\n * trackEmailClick('hello@example.com')\n * ```\n */\nexport function useContactTracking(options: UseContactTrackingOptions = {}): ContactTrackingReturn {\n const { autoTrack = true, debug = false } = options\n const { trackConversion } = useAnalytics()\n \n const trackPhoneClick = useCallback((phoneNumber: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Phone click:', phoneNumber)\n \n trackConversion({\n type: 'phone_call',\n metadata: {\n phoneNumber: phoneNumber.replace(/\\D/g, ''), // Normalize to digits\n rawNumber: phoneNumber,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n const trackEmailClick = useCallback((email: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Email click:', email)\n \n trackConversion({\n type: 'email_click',\n metadata: {\n email,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n // Auto-track tel: and mailto: links\n useEffect(() => {\n if (!autoTrack || typeof document === 'undefined') return\n \n const handleClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n const anchor = target.closest('a')\n if (!anchor) return\n \n const href = anchor.getAttribute('href')\n if (!href) return\n \n if (href.startsWith('tel:')) {\n const phone = href.replace('tel:', '').trim()\n trackPhoneClick(phone, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n } else if (href.startsWith('mailto:')) {\n const email = href.replace('mailto:', '').split('?')[0].trim()\n trackEmailClick(email, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n }\n }\n \n document.addEventListener('click', handleClick, { capture: true })\n \n return () => {\n document.removeEventListener('click', handleClick, { capture: true })\n }\n }, [autoTrack, trackPhoneClick, trackEmailClick])\n \n return {\n trackPhoneClick,\n trackEmailClick,\n }\n}\n\n/**\n * Component wrapper for contact tracking\n * Simply include this component to auto-track all tel: and mailto: links\n * \n * @example\n * ```tsx\n * <ContactTracking />\n * ```\n */\nexport function ContactTracking({ debug = false }: { debug?: boolean }) {\n useContactTracking({ autoTrack: true, debug })\n return null\n}\n"]}
@@ -0,0 +1,70 @@
1
+ import { useAnalytics } from '../chunk-FKVJOT2F.mjs';
2
+ export { AnalyticsProvider, WebVitals, useAnalytics, useTrackEvent } from '../chunk-FKVJOT2F.mjs';
3
+ import '../chunk-NYKRE2FL.mjs';
4
+ import { useCallback, useEffect } from 'react';
5
+
6
+ function useContactTracking(options = {}) {
7
+ const { autoTrack = true, debug = false } = options;
8
+ const { trackConversion } = useAnalytics();
9
+ const trackPhoneClick = useCallback((phoneNumber, metadata) => {
10
+ if (debug) console.log("[Analytics] Phone click:", phoneNumber);
11
+ trackConversion({
12
+ type: "phone_call",
13
+ metadata: {
14
+ phoneNumber: phoneNumber.replace(/\D/g, ""),
15
+ // Normalize to digits
16
+ rawNumber: phoneNumber,
17
+ ...metadata
18
+ }
19
+ });
20
+ }, [trackConversion, debug]);
21
+ const trackEmailClick = useCallback((email, metadata) => {
22
+ if (debug) console.log("[Analytics] Email click:", email);
23
+ trackConversion({
24
+ type: "email_click",
25
+ metadata: {
26
+ email,
27
+ ...metadata
28
+ }
29
+ });
30
+ }, [trackConversion, debug]);
31
+ useEffect(() => {
32
+ if (!autoTrack || typeof document === "undefined") return;
33
+ const handleClick = (e) => {
34
+ const target = e.target;
35
+ const anchor = target.closest("a");
36
+ if (!anchor) return;
37
+ const href = anchor.getAttribute("href");
38
+ if (!href) return;
39
+ if (href.startsWith("tel:")) {
40
+ const phone = href.replace("tel:", "").trim();
41
+ trackPhoneClick(phone, {
42
+ linkText: anchor.textContent?.trim(),
43
+ source: "auto"
44
+ });
45
+ } else if (href.startsWith("mailto:")) {
46
+ const email = href.replace("mailto:", "").split("?")[0].trim();
47
+ trackEmailClick(email, {
48
+ linkText: anchor.textContent?.trim(),
49
+ source: "auto"
50
+ });
51
+ }
52
+ };
53
+ document.addEventListener("click", handleClick, { capture: true });
54
+ return () => {
55
+ document.removeEventListener("click", handleClick, { capture: true });
56
+ };
57
+ }, [autoTrack, trackPhoneClick, trackEmailClick]);
58
+ return {
59
+ trackPhoneClick,
60
+ trackEmailClick
61
+ };
62
+ }
63
+ function ContactTracking({ debug = false }) {
64
+ useContactTracking({ autoTrack: true, debug });
65
+ return null;
66
+ }
67
+
68
+ export { ContactTracking, useContactTracking };
69
+ //# sourceMappingURL=index.mjs.map
70
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/analytics/useContactTracking.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @uptrade/site-kit/analytics - Contact Tracking Hook\n * \n * Tracks phone calls and email clicks as conversions.\n * Use this hook to automatically track tel: and mailto: links,\n * or manually track contact interactions.\n */\n\n'use client'\n\nimport { useCallback, useEffect } from 'react'\nimport { useAnalytics } from './AnalyticsProvider'\n\nexport interface UseContactTrackingOptions {\n /** Automatically track all tel: and mailto: links (default: true) */\n autoTrack?: boolean\n /** Debug mode - logs events to console */\n debug?: boolean\n}\n\nexport interface ContactTrackingReturn {\n /** Manually track a phone call click */\n trackPhoneClick: (phoneNumber: string, metadata?: Record<string, unknown>) => void\n /** Manually track an email click */\n trackEmailClick: (email: string, metadata?: Record<string, unknown>) => void\n}\n\n/**\n * Hook for tracking phone and email contact interactions as conversions.\n * \n * @example\n * ```tsx\n * // Auto-track all tel: and mailto: links\n * useContactTracking()\n * \n * // Manual tracking\n * const { trackPhoneClick, trackEmailClick } = useContactTracking()\n * trackPhoneClick('513-555-1234')\n * trackEmailClick('hello@example.com')\n * ```\n */\nexport function useContactTracking(options: UseContactTrackingOptions = {}): ContactTrackingReturn {\n const { autoTrack = true, debug = false } = options\n const { trackConversion } = useAnalytics()\n \n const trackPhoneClick = useCallback((phoneNumber: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Phone click:', phoneNumber)\n \n trackConversion({\n type: 'phone_call',\n metadata: {\n phoneNumber: phoneNumber.replace(/\\D/g, ''), // Normalize to digits\n rawNumber: phoneNumber,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n const trackEmailClick = useCallback((email: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Email click:', email)\n \n trackConversion({\n type: 'email_click',\n metadata: {\n email,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n // Auto-track tel: and mailto: links\n useEffect(() => {\n if (!autoTrack || typeof document === 'undefined') return\n \n const handleClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n const anchor = target.closest('a')\n if (!anchor) return\n \n const href = anchor.getAttribute('href')\n if (!href) return\n \n if (href.startsWith('tel:')) {\n const phone = href.replace('tel:', '').trim()\n trackPhoneClick(phone, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n } else if (href.startsWith('mailto:')) {\n const email = href.replace('mailto:', '').split('?')[0].trim()\n trackEmailClick(email, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n }\n }\n \n document.addEventListener('click', handleClick, { capture: true })\n \n return () => {\n document.removeEventListener('click', handleClick, { capture: true })\n }\n }, [autoTrack, trackPhoneClick, trackEmailClick])\n \n return {\n trackPhoneClick,\n trackEmailClick,\n }\n}\n\n/**\n * Component wrapper for contact tracking\n * Simply include this component to auto-track all tel: and mailto: links\n * \n * @example\n * ```tsx\n * <ContactTracking />\n * ```\n */\nexport function ContactTracking({ debug = false }: { debug?: boolean }) {\n useContactTracking({ autoTrack: true, debug })\n return null\n}\n"]}
@@ -0,0 +1,57 @@
1
+ 'use strict';
2
+
3
+ var chunkQP5NCO2E_js = require('./chunk-QP5NCO2E.js');
4
+ require('./chunk-EQCVQC35.js');
5
+
6
+
7
+
8
+ Object.defineProperty(exports, "getABTest", {
9
+ enumerable: true,
10
+ get: function () { return chunkQP5NCO2E_js.getABTest; }
11
+ });
12
+ Object.defineProperty(exports, "getContentBlock", {
13
+ enumerable: true,
14
+ get: function () { return chunkQP5NCO2E_js.getContentBlock; }
15
+ });
16
+ Object.defineProperty(exports, "getFAQData", {
17
+ enumerable: true,
18
+ get: function () { return chunkQP5NCO2E_js.getFAQData; }
19
+ });
20
+ Object.defineProperty(exports, "getInternalLinks", {
21
+ enumerable: true,
22
+ get: function () { return chunkQP5NCO2E_js.getInternalLinks; }
23
+ });
24
+ Object.defineProperty(exports, "getManagedScripts", {
25
+ enumerable: true,
26
+ get: function () { return chunkQP5NCO2E_js.getManagedScripts; }
27
+ });
28
+ Object.defineProperty(exports, "getRedirectData", {
29
+ enumerable: true,
30
+ get: function () { return chunkQP5NCO2E_js.getRedirectData; }
31
+ });
32
+ Object.defineProperty(exports, "getRobotsData", {
33
+ enumerable: true,
34
+ get: function () { return chunkQP5NCO2E_js.getRobotsData; }
35
+ });
36
+ Object.defineProperty(exports, "getSEOPageData", {
37
+ enumerable: true,
38
+ get: function () { return chunkQP5NCO2E_js.getSEOPageData; }
39
+ });
40
+ Object.defineProperty(exports, "getSchemaMarkups", {
41
+ enumerable: true,
42
+ get: function () { return chunkQP5NCO2E_js.getSchemaMarkups; }
43
+ });
44
+ Object.defineProperty(exports, "getSitemapEntries", {
45
+ enumerable: true,
46
+ get: function () { return chunkQP5NCO2E_js.getSitemapEntries; }
47
+ });
48
+ Object.defineProperty(exports, "recordABImpression", {
49
+ enumerable: true,
50
+ get: function () { return chunkQP5NCO2E_js.recordABImpression; }
51
+ });
52
+ Object.defineProperty(exports, "registerSitemap", {
53
+ enumerable: true,
54
+ get: function () { return chunkQP5NCO2E_js.registerSitemap; }
55
+ });
56
+ //# sourceMappingURL=api-N35S3EES.js.map
57
+ //# sourceMappingURL=api-N35S3EES.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"api-N35S3EES.js"}
@@ -0,0 +1,4 @@
1
+ export { getABTest, getContentBlock, getFAQData, getInternalLinks, getManagedScripts, getRedirectData, getRobotsData, getSEOPageData, getSchemaMarkups, getSitemapEntries, recordABImpression, registerSitemap } from './chunk-7H6I3ECV.mjs';
2
+ import './chunk-NYKRE2FL.mjs';
3
+ //# sourceMappingURL=api-SYBTK7Z7.mjs.map
4
+ //# sourceMappingURL=api-SYBTK7Z7.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"api-SYBTK7Z7.mjs"}