@marvalt/madapter 1.0.14 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/mautic-client.d.ts.map +1 -1
- package/dist/generators/mautic-generator.d.ts +5 -0
- package/dist/generators/mautic-generator.d.ts.map +1 -1
- package/dist/index.cjs +433 -427
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +14 -9
- package/dist/index.esm.js +433 -426
- package/dist/index.esm.js.map +1 -1
- package/dist/react/components/MauticTracking.d.ts.map +1 -1
- package/dist/service/mautic-service.d.ts +1 -1
- package/dist/service/mautic-service.d.ts.map +1 -1
- package/dist/types/config.d.ts +8 -6
- package/dist/types/config.d.ts.map +1 -1
- package/dist/utils/config.d.ts +0 -2
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var reactQuery = require('@tanstack/react-query');
|
|
4
3
|
var fs = require('fs');
|
|
5
4
|
var path = require('path');
|
|
6
5
|
var React = require('react');
|
|
6
|
+
var reactQuery = require('@tanstack/react-query');
|
|
7
7
|
|
|
8
8
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
9
9
|
/**
|
|
@@ -24,18 +24,17 @@ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentS
|
|
|
24
24
|
*/
|
|
25
25
|
class MauticClient {
|
|
26
26
|
constructor(config) {
|
|
27
|
+
this.baseUrl = '';
|
|
27
28
|
this.config = config;
|
|
28
|
-
if (config.authMode === 'cloudflare_proxy' && config.cloudflareWorkerUrl
|
|
29
|
+
if (config.authMode === 'cloudflare_proxy' && config.cloudflareWorkerUrl) {
|
|
29
30
|
// Cloudflare Worker proxy (recommended - uses Secrets Store)
|
|
30
31
|
this.proxyUrl = config.cloudflareWorkerUrl;
|
|
31
|
-
this.appId = config.appId;
|
|
32
|
-
this.workerSecret = config.workerSecret;
|
|
33
32
|
this.useProxy = true;
|
|
34
33
|
this.isConfigured = true;
|
|
35
34
|
}
|
|
36
35
|
else if (config.authMode === 'direct' && config.apiUrl) {
|
|
37
36
|
// Direct Mautic API access (legacy - for local development only)
|
|
38
|
-
this.baseUrl = config.apiUrl;
|
|
37
|
+
this.baseUrl = config.apiUrl || '';
|
|
39
38
|
this.useProxy = false;
|
|
40
39
|
this.isConfigured = true;
|
|
41
40
|
}
|
|
@@ -50,17 +49,7 @@ class MauticClient {
|
|
|
50
49
|
throw new Error('Mautic service not properly configured. Check your configuration.');
|
|
51
50
|
}
|
|
52
51
|
}
|
|
53
|
-
getAuthHeaders() {
|
|
54
|
-
if (this.useProxy) {
|
|
55
|
-
return {
|
|
56
|
-
'x-app-id': this.appId || '',
|
|
57
|
-
'x-app-secret': this.workerSecret || '',
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
return {};
|
|
62
|
-
}
|
|
63
|
-
}
|
|
52
|
+
getAuthHeaders() { return {}; }
|
|
64
53
|
async makeRequest(endpoint, options = {}) {
|
|
65
54
|
this.validateConfiguration();
|
|
66
55
|
let url;
|
|
@@ -86,7 +75,7 @@ class MauticClient {
|
|
|
86
75
|
const isFormSubmission = endpoint.startsWith('/form/submit') ||
|
|
87
76
|
(endpoint.startsWith('/forms/') && endpoint.includes('/submit'));
|
|
88
77
|
const headers = {
|
|
89
|
-
|
|
78
|
+
// no app headers in proxy mode
|
|
90
79
|
...options.headers,
|
|
91
80
|
};
|
|
92
81
|
// Default JSON only for non-form submissions when a body exists and no explicit content-type provided
|
|
@@ -319,8 +308,6 @@ const createMauticConfig = (overrides = {}) => {
|
|
|
319
308
|
authMode: getEnvVar('VITE_AUTH_MODE') || getEnvVar('VITE_MAUTIC_AUTH_MODE') || 'cloudflare_proxy',
|
|
320
309
|
apiUrl: getEnvVar('VITE_MAUTIC_URL'),
|
|
321
310
|
cloudflareWorkerUrl: getEnvVar('VITE_MAUTIC_PROXY_URL'),
|
|
322
|
-
appId: getEnvVar('VITE_FRONTEND_ID'),
|
|
323
|
-
workerSecret: getEnvVar('VITE_FRONTEND_SECRET'),
|
|
324
311
|
timeout: parseInt(getEnvVar('VITE_MAUTIC_TIMEOUT') || '30000'),
|
|
325
312
|
retries: parseInt(getEnvVar('VITE_MAUTIC_RETRIES') || '3'),
|
|
326
313
|
...overrides,
|
|
@@ -330,10 +317,6 @@ const createMauticConfig = (overrides = {}) => {
|
|
|
330
317
|
if (merged.authMode === 'cloudflare_proxy') {
|
|
331
318
|
if (!merged.cloudflareWorkerUrl)
|
|
332
319
|
errors.push('cloudflareWorkerUrl is required for cloudflare_proxy mode');
|
|
333
|
-
if (!merged.appId)
|
|
334
|
-
errors.push('appId is required for cloudflare_proxy mode');
|
|
335
|
-
if (!merged.workerSecret)
|
|
336
|
-
errors.push('workerSecret is required for cloudflare_proxy mode');
|
|
337
320
|
}
|
|
338
321
|
if (merged.authMode === 'direct') {
|
|
339
322
|
if (!merged.apiUrl)
|
|
@@ -356,12 +339,6 @@ const validateMauticConfig = (config) => {
|
|
|
356
339
|
if (!config.cloudflareWorkerUrl) {
|
|
357
340
|
errors.push('cloudflareWorkerUrl is required for cloudflare_proxy mode');
|
|
358
341
|
}
|
|
359
|
-
if (!config.appId) {
|
|
360
|
-
errors.push('appId is required for cloudflare_proxy mode');
|
|
361
|
-
}
|
|
362
|
-
if (!config.workerSecret) {
|
|
363
|
-
errors.push('workerSecret is required for cloudflare_proxy mode');
|
|
364
|
-
}
|
|
365
342
|
}
|
|
366
343
|
else if (config.authMode === 'direct') {
|
|
367
344
|
if (!config.apiUrl) {
|
|
@@ -403,7 +380,7 @@ const mergeMauticConfig = (base, overrides) => {
|
|
|
403
380
|
*/
|
|
404
381
|
const isMauticEnabled = (config) => {
|
|
405
382
|
if (config.authMode === 'cloudflare_proxy') {
|
|
406
|
-
return !!
|
|
383
|
+
return !!config.cloudflareWorkerUrl;
|
|
407
384
|
}
|
|
408
385
|
else if (config.authMode === 'direct') {
|
|
409
386
|
return !!config.apiUrl;
|
|
@@ -418,323 +395,12 @@ const getMauticConfigSummary = (config) => {
|
|
|
418
395
|
authMode: config.authMode,
|
|
419
396
|
hasApiUrl: !!config.apiUrl,
|
|
420
397
|
hasCloudflareWorkerUrl: !!config.cloudflareWorkerUrl,
|
|
421
|
-
hasAppId: !!config.appId,
|
|
422
|
-
hasWorkerSecret: !!config.workerSecret,
|
|
423
398
|
timeout: config.timeout,
|
|
424
399
|
retries: config.retries,
|
|
425
400
|
isEnabled: isMauticEnabled(config),
|
|
426
401
|
};
|
|
427
402
|
};
|
|
428
403
|
|
|
429
|
-
/**
|
|
430
|
-
* @license GPL-3.0-or-later
|
|
431
|
-
*
|
|
432
|
-
* This file is part of the MarVAlt Open SDK.
|
|
433
|
-
* Copyright (c) 2025 Vibune Pty Ltd.
|
|
434
|
-
*
|
|
435
|
-
* This program is free software: you can redistribute it and/or modify
|
|
436
|
-
* it under the terms of the GNU General Public License as published by
|
|
437
|
-
* the Free Software Foundation, either version 3 of the License, or
|
|
438
|
-
* (at your option) any later version.
|
|
439
|
-
*
|
|
440
|
-
* This program is distributed in the hope that it will be useful,
|
|
441
|
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
442
|
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
443
|
-
* See the GNU General Public License for more details.
|
|
444
|
-
*/
|
|
445
|
-
// Create a default client instance (will be overridden by provider)
|
|
446
|
-
let defaultClient = null;
|
|
447
|
-
/**
|
|
448
|
-
* Set the default Mautic client for hooks
|
|
449
|
-
*/
|
|
450
|
-
const setMauticClient = (client) => {
|
|
451
|
-
defaultClient = client;
|
|
452
|
-
};
|
|
453
|
-
/**
|
|
454
|
-
* Get the current Mautic client
|
|
455
|
-
*/
|
|
456
|
-
const getMauticClient = () => {
|
|
457
|
-
if (!defaultClient) {
|
|
458
|
-
// Lazy initialize the client from environment if not set by provider/service
|
|
459
|
-
const config = createMauticConfig();
|
|
460
|
-
defaultClient = new MauticClient(config);
|
|
461
|
-
}
|
|
462
|
-
return defaultClient;
|
|
463
|
-
};
|
|
464
|
-
/**
|
|
465
|
-
* Custom hook for submitting forms to Mautic
|
|
466
|
-
*/
|
|
467
|
-
const useMauticFormSubmission = () => {
|
|
468
|
-
const queryClient = reactQuery.useQueryClient();
|
|
469
|
-
return reactQuery.useMutation({
|
|
470
|
-
mutationFn: (submission) => {
|
|
471
|
-
const client = getMauticClient();
|
|
472
|
-
return client.submitForm(submission.formId, submission);
|
|
473
|
-
},
|
|
474
|
-
onSuccess: (data, variables) => {
|
|
475
|
-
if (undefined?.DEV) {
|
|
476
|
-
console.log('Mautic form submission successful:', data);
|
|
477
|
-
}
|
|
478
|
-
// Invalidate related queries
|
|
479
|
-
queryClient.invalidateQueries({ queryKey: ['mautic-contacts'] });
|
|
480
|
-
// Track the submission event
|
|
481
|
-
if (variables.contact?.email) {
|
|
482
|
-
const client = getMauticClient();
|
|
483
|
-
client.trackEvent('form_submission', {
|
|
484
|
-
formId: variables.formId,
|
|
485
|
-
email: variables.contact.email
|
|
486
|
-
}).catch(console.error);
|
|
487
|
-
}
|
|
488
|
-
},
|
|
489
|
-
onError: (error) => {
|
|
490
|
-
console.error('Mautic form submission failed:', error);
|
|
491
|
-
},
|
|
492
|
-
});
|
|
493
|
-
};
|
|
494
|
-
/**
|
|
495
|
-
* Custom hook for creating Mautic contacts
|
|
496
|
-
*/
|
|
497
|
-
const useMauticCreateContact = () => {
|
|
498
|
-
const queryClient = reactQuery.useQueryClient();
|
|
499
|
-
return reactQuery.useMutation({
|
|
500
|
-
mutationFn: (contact) => {
|
|
501
|
-
const client = getMauticClient();
|
|
502
|
-
return client.createContact(contact);
|
|
503
|
-
},
|
|
504
|
-
onSuccess: (data, variables) => {
|
|
505
|
-
if (undefined?.DEV) {
|
|
506
|
-
console.log('Mautic contact created:', data);
|
|
507
|
-
}
|
|
508
|
-
// Invalidate contacts queries
|
|
509
|
-
queryClient.invalidateQueries({ queryKey: ['mautic-contacts'] });
|
|
510
|
-
queryClient.invalidateQueries({ queryKey: ['mautic-contact', variables.email] });
|
|
511
|
-
},
|
|
512
|
-
onError: (error) => {
|
|
513
|
-
console.error('Failed to create Mautic contact:', error);
|
|
514
|
-
},
|
|
515
|
-
});
|
|
516
|
-
};
|
|
517
|
-
/**
|
|
518
|
-
* Custom hook for updating Mautic contacts
|
|
519
|
-
*/
|
|
520
|
-
const useMauticUpdateContact = () => {
|
|
521
|
-
const queryClient = reactQuery.useQueryClient();
|
|
522
|
-
return reactQuery.useMutation({
|
|
523
|
-
mutationFn: ({ contactId, contact }) => {
|
|
524
|
-
const client = getMauticClient();
|
|
525
|
-
return client.updateContact(contactId, contact);
|
|
526
|
-
},
|
|
527
|
-
onSuccess: (data, variables) => {
|
|
528
|
-
if (undefined?.DEV) {
|
|
529
|
-
console.log('Mautic contact updated:', data);
|
|
530
|
-
}
|
|
531
|
-
// Invalidate related queries
|
|
532
|
-
queryClient.invalidateQueries({ queryKey: ['mautic-contacts'] });
|
|
533
|
-
queryClient.invalidateQueries({ queryKey: ['mautic-contact', variables.contactId] });
|
|
534
|
-
},
|
|
535
|
-
onError: (error) => {
|
|
536
|
-
console.error('Failed to update Mautic contact:', error);
|
|
537
|
-
},
|
|
538
|
-
});
|
|
539
|
-
};
|
|
540
|
-
/**
|
|
541
|
-
* Custom hook for fetching Mautic contact by email
|
|
542
|
-
*/
|
|
543
|
-
const useMauticContactByEmail = (email) => {
|
|
544
|
-
return reactQuery.useQuery({
|
|
545
|
-
queryKey: ['mautic-contact', email],
|
|
546
|
-
queryFn: () => {
|
|
547
|
-
const client = getMauticClient();
|
|
548
|
-
return client.getContactByEmail(email);
|
|
549
|
-
},
|
|
550
|
-
enabled: !!email && email.includes('@'),
|
|
551
|
-
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
552
|
-
gcTime: 10 * 60 * 1000,
|
|
553
|
-
});
|
|
554
|
-
};
|
|
555
|
-
/**
|
|
556
|
-
* Custom hook for fetching Mautic forms
|
|
557
|
-
*/
|
|
558
|
-
const useMauticForms = () => {
|
|
559
|
-
return reactQuery.useQuery({
|
|
560
|
-
queryKey: ['mautic-forms'],
|
|
561
|
-
queryFn: () => {
|
|
562
|
-
const client = getMauticClient();
|
|
563
|
-
return client.getForms();
|
|
564
|
-
},
|
|
565
|
-
staleTime: 30 * 60 * 1000, // Forms don't change often
|
|
566
|
-
gcTime: 60 * 60 * 1000,
|
|
567
|
-
});
|
|
568
|
-
};
|
|
569
|
-
/**
|
|
570
|
-
* Custom hook for fetching a specific Mautic form
|
|
571
|
-
*/
|
|
572
|
-
const useMauticForm = (formId) => {
|
|
573
|
-
return reactQuery.useQuery({
|
|
574
|
-
queryKey: ['mautic-form', formId],
|
|
575
|
-
queryFn: () => {
|
|
576
|
-
const client = getMauticClient();
|
|
577
|
-
return client.getForm(formId);
|
|
578
|
-
},
|
|
579
|
-
enabled: !!formId,
|
|
580
|
-
staleTime: 30 * 60 * 1000,
|
|
581
|
-
gcTime: 60 * 60 * 1000,
|
|
582
|
-
});
|
|
583
|
-
};
|
|
584
|
-
/**
|
|
585
|
-
* Custom hook for tracking Mautic events
|
|
586
|
-
*/
|
|
587
|
-
const useMauticEventTracking = () => {
|
|
588
|
-
return reactQuery.useMutation({
|
|
589
|
-
mutationFn: ({ email, eventName, eventData }) => {
|
|
590
|
-
const client = getMauticClient();
|
|
591
|
-
return client.trackEvent(eventName, {
|
|
592
|
-
email,
|
|
593
|
-
...(eventData || {})
|
|
594
|
-
});
|
|
595
|
-
},
|
|
596
|
-
onSuccess: (data, variables) => {
|
|
597
|
-
if (undefined?.DEV) {
|
|
598
|
-
console.log('Mautic event tracked successfully:', variables.eventName);
|
|
599
|
-
}
|
|
600
|
-
},
|
|
601
|
-
onError: (error, variables) => {
|
|
602
|
-
console.error('Failed to track Mautic event:', variables.eventName, error);
|
|
603
|
-
},
|
|
604
|
-
});
|
|
605
|
-
};
|
|
606
|
-
/**
|
|
607
|
-
* Custom hook for adding tags to contacts
|
|
608
|
-
*/
|
|
609
|
-
const useMauticAddTags = () => {
|
|
610
|
-
const queryClient = reactQuery.useQueryClient();
|
|
611
|
-
return reactQuery.useMutation({
|
|
612
|
-
mutationFn: ({ contactId, tags }) => {
|
|
613
|
-
const client = getMauticClient();
|
|
614
|
-
return client.addTagToContact(contactId, tags);
|
|
615
|
-
},
|
|
616
|
-
onSuccess: (data, variables) => {
|
|
617
|
-
if (undefined?.DEV) {
|
|
618
|
-
console.log('Tags added to Mautic contact:', variables.tags);
|
|
619
|
-
}
|
|
620
|
-
// Invalidate contact queries
|
|
621
|
-
queryClient.invalidateQueries({ queryKey: ['mautic-contact', variables.contactId] });
|
|
622
|
-
},
|
|
623
|
-
onError: (error) => {
|
|
624
|
-
console.error('Failed to add tags to Mautic contact:', error);
|
|
625
|
-
},
|
|
626
|
-
});
|
|
627
|
-
};
|
|
628
|
-
/**
|
|
629
|
-
* Custom hook for removing tags from contacts
|
|
630
|
-
*/
|
|
631
|
-
const useMauticRemoveTags = () => {
|
|
632
|
-
const queryClient = reactQuery.useQueryClient();
|
|
633
|
-
return reactQuery.useMutation({
|
|
634
|
-
mutationFn: ({ contactId, tags }) => {
|
|
635
|
-
const client = getMauticClient();
|
|
636
|
-
return client.removeTagFromContact(contactId, tags);
|
|
637
|
-
},
|
|
638
|
-
onSuccess: (data, variables) => {
|
|
639
|
-
if (undefined?.DEV) {
|
|
640
|
-
console.log('Tags removed from Mautic contact:', variables.tags);
|
|
641
|
-
}
|
|
642
|
-
// Invalidate contact queries
|
|
643
|
-
queryClient.invalidateQueries({ queryKey: ['mautic-contact', variables.contactId] });
|
|
644
|
-
},
|
|
645
|
-
onError: (error) => {
|
|
646
|
-
console.error('Failed to remove tags from Mautic contact:', error);
|
|
647
|
-
},
|
|
648
|
-
});
|
|
649
|
-
};
|
|
650
|
-
/**
|
|
651
|
-
* Custom hook for getting contact tags
|
|
652
|
-
*/
|
|
653
|
-
const useMauticContactTags = (contactId) => {
|
|
654
|
-
return reactQuery.useQuery({
|
|
655
|
-
queryKey: ['mautic-contact-tags', contactId],
|
|
656
|
-
queryFn: () => {
|
|
657
|
-
const client = getMauticClient();
|
|
658
|
-
return client.getContactTags(contactId);
|
|
659
|
-
},
|
|
660
|
-
enabled: !!contactId,
|
|
661
|
-
staleTime: 5 * 60 * 1000,
|
|
662
|
-
gcTime: 10 * 60 * 1000,
|
|
663
|
-
});
|
|
664
|
-
};
|
|
665
|
-
/**
|
|
666
|
-
* Custom hook for getting all tags
|
|
667
|
-
*/
|
|
668
|
-
const useMauticTags = () => {
|
|
669
|
-
return reactQuery.useQuery({
|
|
670
|
-
queryKey: ['mautic-tags'],
|
|
671
|
-
queryFn: () => {
|
|
672
|
-
const client = getMauticClient();
|
|
673
|
-
return client.getTags();
|
|
674
|
-
},
|
|
675
|
-
staleTime: 30 * 60 * 1000,
|
|
676
|
-
gcTime: 60 * 60 * 1000,
|
|
677
|
-
});
|
|
678
|
-
};
|
|
679
|
-
/**
|
|
680
|
-
* Custom hook for getting segments
|
|
681
|
-
*/
|
|
682
|
-
const useMauticSegments = () => {
|
|
683
|
-
return reactQuery.useQuery({
|
|
684
|
-
queryKey: ['mautic-segments'],
|
|
685
|
-
queryFn: () => {
|
|
686
|
-
const client = getMauticClient();
|
|
687
|
-
return client.getSegments();
|
|
688
|
-
},
|
|
689
|
-
staleTime: 30 * 60 * 1000,
|
|
690
|
-
gcTime: 60 * 60 * 1000,
|
|
691
|
-
});
|
|
692
|
-
};
|
|
693
|
-
/**
|
|
694
|
-
* Custom hook for adding contact to segment
|
|
695
|
-
*/
|
|
696
|
-
const useMauticAddToSegment = () => {
|
|
697
|
-
const queryClient = reactQuery.useQueryClient();
|
|
698
|
-
return reactQuery.useMutation({
|
|
699
|
-
mutationFn: ({ contactId, segmentId }) => {
|
|
700
|
-
const client = getMauticClient();
|
|
701
|
-
return client.addContactToSegment(contactId, segmentId);
|
|
702
|
-
},
|
|
703
|
-
onSuccess: (data, variables) => {
|
|
704
|
-
if (undefined?.DEV) {
|
|
705
|
-
console.log('Contact added to segment:', variables.segmentId);
|
|
706
|
-
}
|
|
707
|
-
// Invalidate contact queries
|
|
708
|
-
queryClient.invalidateQueries({ queryKey: ['mautic-contact', variables.contactId] });
|
|
709
|
-
},
|
|
710
|
-
onError: (error) => {
|
|
711
|
-
console.error('Failed to add contact to segment:', error);
|
|
712
|
-
},
|
|
713
|
-
});
|
|
714
|
-
};
|
|
715
|
-
/**
|
|
716
|
-
* Custom hook for removing contact from segment
|
|
717
|
-
*/
|
|
718
|
-
const useMauticRemoveFromSegment = () => {
|
|
719
|
-
const queryClient = reactQuery.useQueryClient();
|
|
720
|
-
return reactQuery.useMutation({
|
|
721
|
-
mutationFn: ({ contactId, segmentId }) => {
|
|
722
|
-
const client = getMauticClient();
|
|
723
|
-
return client.removeContactFromSegment(contactId, segmentId);
|
|
724
|
-
},
|
|
725
|
-
onSuccess: (data, variables) => {
|
|
726
|
-
if (undefined?.DEV) {
|
|
727
|
-
console.log('Contact removed from segment:', variables.segmentId);
|
|
728
|
-
}
|
|
729
|
-
// Invalidate contact queries
|
|
730
|
-
queryClient.invalidateQueries({ queryKey: ['mautic-contact', variables.contactId] });
|
|
731
|
-
},
|
|
732
|
-
onError: (error) => {
|
|
733
|
-
console.error('Failed to remove contact from segment:', error);
|
|
734
|
-
},
|
|
735
|
-
});
|
|
736
|
-
};
|
|
737
|
-
|
|
738
404
|
/**
|
|
739
405
|
* @license GPL-3.0-or-later
|
|
740
406
|
*
|
|
@@ -836,9 +502,19 @@ class MauticService {
|
|
|
836
502
|
return this.client.trackEvent(eventName, eventData);
|
|
837
503
|
}
|
|
838
504
|
}
|
|
839
|
-
// Export configured instance
|
|
840
|
-
|
|
841
|
-
|
|
505
|
+
// Export configured instance (guarded to avoid throwing at import time)
|
|
506
|
+
exports.mauticService = null;
|
|
507
|
+
try {
|
|
508
|
+
exports.mauticService = new MauticService();
|
|
509
|
+
// Initialize the default client for hooks
|
|
510
|
+
// Lazy import to avoid circular/side-effect issues in some environments
|
|
511
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
512
|
+
const { setMauticClient } = require('../react/hooks/useMautic');
|
|
513
|
+
setMauticClient(exports.mauticService['client']);
|
|
514
|
+
}
|
|
515
|
+
catch {
|
|
516
|
+
// Silently skip initialization when environment is not configured
|
|
517
|
+
}
|
|
842
518
|
|
|
843
519
|
/**
|
|
844
520
|
* @license GPL-3.0-or-later
|
|
@@ -858,17 +534,57 @@ setMauticClient(mauticService['client']);
|
|
|
858
534
|
*/
|
|
859
535
|
class MauticGenerator {
|
|
860
536
|
constructor(config) {
|
|
537
|
+
this.cachedToken = null;
|
|
861
538
|
this.config = config;
|
|
862
539
|
this.client = new MauticClient({
|
|
863
540
|
authMode: config.authMode,
|
|
864
541
|
apiUrl: config.apiUrl,
|
|
865
542
|
cloudflareWorkerUrl: config.cloudflareWorkerUrl,
|
|
866
|
-
|
|
867
|
-
|
|
543
|
+
clientId: config.clientId,
|
|
544
|
+
clientSecret: config.clientSecret,
|
|
545
|
+
cfAccessClientId: config.cfAccessClientId,
|
|
546
|
+
cfAccessClientSecret: config.cfAccessClientSecret,
|
|
868
547
|
timeout: config.timeout,
|
|
869
548
|
retries: config.retries,
|
|
870
549
|
});
|
|
871
550
|
}
|
|
551
|
+
/**
|
|
552
|
+
* Get OAuth2 token for direct mode API calls
|
|
553
|
+
*/
|
|
554
|
+
async getOAuth2Token() {
|
|
555
|
+
if (this.cachedToken && this.cachedToken.expires_at > Date.now() + 300000) {
|
|
556
|
+
console.log('🔑 Using cached OAuth2 token');
|
|
557
|
+
return this.cachedToken.access_token;
|
|
558
|
+
}
|
|
559
|
+
if (!this.config.clientId || !this.config.clientSecret) {
|
|
560
|
+
throw new Error('OAuth2 credentials (clientId, clientSecret) required for direct mode');
|
|
561
|
+
}
|
|
562
|
+
console.log('🔑 Fetching new OAuth2 token...');
|
|
563
|
+
const tokenUrl = `${this.config.apiUrl}/oauth/v2/token`;
|
|
564
|
+
const body = new URLSearchParams({
|
|
565
|
+
grant_type: 'client_credentials',
|
|
566
|
+
client_id: this.config.clientId,
|
|
567
|
+
client_secret: this.config.clientSecret,
|
|
568
|
+
});
|
|
569
|
+
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
|
|
570
|
+
if (this.config.cfAccessClientId && this.config.cfAccessClientSecret) {
|
|
571
|
+
headers['CF-Access-Client-Id'] = this.config.cfAccessClientId;
|
|
572
|
+
headers['CF-Access-Client-Secret'] = this.config.cfAccessClientSecret;
|
|
573
|
+
console.log('🔐 Added CF Access headers to OAuth2 token request');
|
|
574
|
+
}
|
|
575
|
+
const resp = await fetch(tokenUrl, { method: 'POST', headers, body: body.toString() });
|
|
576
|
+
if (!resp.ok) {
|
|
577
|
+
const errText = await resp.text();
|
|
578
|
+
throw new Error(`OAuth2 token failed: ${resp.status} ${errText}`);
|
|
579
|
+
}
|
|
580
|
+
const data = await resp.json();
|
|
581
|
+
this.cachedToken = {
|
|
582
|
+
access_token: data.access_token,
|
|
583
|
+
expires_at: Date.now() + (data.expires_in * 1000),
|
|
584
|
+
};
|
|
585
|
+
console.log('✅ OAuth2 token cached');
|
|
586
|
+
return this.cachedToken.access_token;
|
|
587
|
+
}
|
|
872
588
|
/**
|
|
873
589
|
* Generate static data for Mautic forms
|
|
874
590
|
*/
|
|
@@ -902,7 +618,7 @@ class MauticGenerator {
|
|
|
902
618
|
// Include other important form properties
|
|
903
619
|
formType: formDetails.formType || 'standalone',
|
|
904
620
|
// Extract fields with validation and properties
|
|
905
|
-
fields: (formDetails.fields || []).map(field => ({
|
|
621
|
+
fields: (formDetails.fields || []).map((field) => ({
|
|
906
622
|
id: field.id,
|
|
907
623
|
label: field.label,
|
|
908
624
|
alias: field.alias,
|
|
@@ -921,7 +637,7 @@ class MauticGenerator {
|
|
|
921
637
|
}
|
|
922
638
|
})),
|
|
923
639
|
// Extract actions
|
|
924
|
-
actions: (formDetails.actions || []).map(action => ({
|
|
640
|
+
actions: (formDetails.actions || []).map((action) => ({
|
|
925
641
|
id: action.id,
|
|
926
642
|
name: action.name,
|
|
927
643
|
type: action.type,
|
|
@@ -945,10 +661,10 @@ class MauticGenerator {
|
|
|
945
661
|
const staticData = {
|
|
946
662
|
generated_at: new Date().toISOString(),
|
|
947
663
|
total_forms: forms.length,
|
|
948
|
-
forms: forms.map(form => ({
|
|
664
|
+
forms: forms.map((form) => ({
|
|
949
665
|
id: parseInt(form.id),
|
|
950
666
|
name: form.name,
|
|
951
|
-
alias: form.alias
|
|
667
|
+
alias: String(form.alias ?? (form.name || '').toLowerCase().replace(/\s+/g, '-')),
|
|
952
668
|
description: form.description,
|
|
953
669
|
isPublished: form.isPublished,
|
|
954
670
|
fields: form.fields,
|
|
@@ -995,49 +711,44 @@ class MauticGenerator {
|
|
|
995
711
|
* Fetch list of forms from Mautic
|
|
996
712
|
*/
|
|
997
713
|
async fetchMauticFormsList() {
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
const url = `${baseUrl}?endpoint=/forms`;
|
|
1002
|
-
const headers = {
|
|
1003
|
-
'Content-Type': 'application/json',
|
|
1004
|
-
};
|
|
1005
|
-
if (this.config.appId) {
|
|
1006
|
-
headers['x-app-id'] = this.config.appId;
|
|
714
|
+
if (this.config.authMode === 'cloudflare_proxy') {
|
|
715
|
+
const forms = await this.client.getForms();
|
|
716
|
+
return Array.isArray(forms) ? forms : [];
|
|
1007
717
|
}
|
|
1008
|
-
|
|
1009
|
-
|
|
718
|
+
// Direct mode with OAuth2
|
|
719
|
+
const token = await this.getOAuth2Token();
|
|
720
|
+
const url = `${this.config.apiUrl}/api/forms`;
|
|
721
|
+
const headers = { 'Authorization': `Bearer ${token}` };
|
|
722
|
+
if (this.config.cfAccessClientId && this.config.cfAccessClientSecret) {
|
|
723
|
+
headers['CF-Access-Client-Id'] = this.config.cfAccessClientId;
|
|
724
|
+
headers['CF-Access-Client-Secret'] = this.config.cfAccessClientSecret;
|
|
1010
725
|
}
|
|
1011
|
-
const
|
|
1012
|
-
if (!
|
|
1013
|
-
throw new Error(`Failed to fetch forms
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
const forms = data.forms;
|
|
1017
|
-
return Array.isArray(forms) ? forms : [];
|
|
726
|
+
const resp = await fetch(url, { headers });
|
|
727
|
+
if (!resp.ok)
|
|
728
|
+
throw new Error(`Failed to fetch forms: ${resp.status}`);
|
|
729
|
+
const data = await resp.json();
|
|
730
|
+
return Array.isArray(data.forms) ? data.forms : [];
|
|
1018
731
|
}
|
|
1019
732
|
/**
|
|
1020
733
|
* Fetch individual form details from Mautic
|
|
1021
734
|
*/
|
|
1022
735
|
async fetchMauticForm(formId) {
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
throw new Error('VITE_MAUTIC_PROXY_URL not configured');
|
|
1026
|
-
const url = `${baseUrl}?endpoint=/forms/${formId}`;
|
|
1027
|
-
const headers = {
|
|
1028
|
-
'Content-Type': 'application/json',
|
|
1029
|
-
};
|
|
1030
|
-
if (this.config.appId) {
|
|
1031
|
-
headers['x-app-id'] = this.config.appId;
|
|
1032
|
-
}
|
|
1033
|
-
if (this.config.workerSecret) {
|
|
1034
|
-
headers['x-app-secret'] = this.config.workerSecret;
|
|
736
|
+
if (this.config.authMode === 'cloudflare_proxy') {
|
|
737
|
+
return this.client.getForm(parseInt(formId, 10));
|
|
1035
738
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
739
|
+
// Direct mode with OAuth2
|
|
740
|
+
const token = await this.getOAuth2Token();
|
|
741
|
+
const url = `${this.config.apiUrl}/api/forms/${formId}`;
|
|
742
|
+
const headers = { 'Authorization': `Bearer ${token}` };
|
|
743
|
+
if (this.config.cfAccessClientId && this.config.cfAccessClientSecret) {
|
|
744
|
+
headers['CF-Access-Client-Id'] = this.config.cfAccessClientId;
|
|
745
|
+
headers['CF-Access-Client-Secret'] = this.config.cfAccessClientSecret;
|
|
1039
746
|
}
|
|
1040
|
-
|
|
747
|
+
const resp = await fetch(url, { headers });
|
|
748
|
+
if (!resp.ok)
|
|
749
|
+
throw new Error(`Failed to fetch form ${formId}: ${resp.status}`);
|
|
750
|
+
const data = await resp.json();
|
|
751
|
+
return data.form || data;
|
|
1041
752
|
}
|
|
1042
753
|
}
|
|
1043
754
|
/**
|
|
@@ -2403,6 +2114,315 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
2403
2114
|
|
|
2404
2115
|
var jsxRuntimeExports = jsxRuntime.exports;
|
|
2405
2116
|
|
|
2117
|
+
/**
|
|
2118
|
+
* @license GPL-3.0-or-later
|
|
2119
|
+
*
|
|
2120
|
+
* This file is part of the MarVAlt Open SDK.
|
|
2121
|
+
* Copyright (c) 2025 Vibune Pty Ltd.
|
|
2122
|
+
*
|
|
2123
|
+
* This program is free software: you can redistribute it and/or modify
|
|
2124
|
+
* it under the terms of the GNU General Public License as published by
|
|
2125
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
2126
|
+
* (at your option) any later version.
|
|
2127
|
+
*
|
|
2128
|
+
* This program is distributed in the hope that it will be useful,
|
|
2129
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
2130
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
2131
|
+
* See the GNU General Public License for more details.
|
|
2132
|
+
*/
|
|
2133
|
+
// Create a default client instance (will be overridden by provider)
|
|
2134
|
+
let defaultClient = null;
|
|
2135
|
+
/**
|
|
2136
|
+
* Set the default Mautic client for hooks
|
|
2137
|
+
*/
|
|
2138
|
+
const setMauticClient = (client) => {
|
|
2139
|
+
defaultClient = client;
|
|
2140
|
+
};
|
|
2141
|
+
/**
|
|
2142
|
+
* Get the current Mautic client
|
|
2143
|
+
*/
|
|
2144
|
+
const getMauticClient = () => {
|
|
2145
|
+
if (!defaultClient) {
|
|
2146
|
+
// Lazy initialize the client from environment if not set by provider/service
|
|
2147
|
+
const config = createMauticConfig();
|
|
2148
|
+
defaultClient = new MauticClient(config);
|
|
2149
|
+
}
|
|
2150
|
+
return defaultClient;
|
|
2151
|
+
};
|
|
2152
|
+
/**
|
|
2153
|
+
* Custom hook for submitting forms to Mautic
|
|
2154
|
+
*/
|
|
2155
|
+
const useMauticFormSubmission = () => {
|
|
2156
|
+
const queryClient = reactQuery.useQueryClient();
|
|
2157
|
+
return reactQuery.useMutation({
|
|
2158
|
+
mutationFn: (submission) => {
|
|
2159
|
+
const client = getMauticClient();
|
|
2160
|
+
return client.submitForm(submission.formId, submission);
|
|
2161
|
+
},
|
|
2162
|
+
onSuccess: (data, variables) => {
|
|
2163
|
+
if (process.env.NODE_ENV === 'development') {
|
|
2164
|
+
console.log('Mautic form submission successful:', data);
|
|
2165
|
+
}
|
|
2166
|
+
// Invalidate related queries
|
|
2167
|
+
queryClient.invalidateQueries({ queryKey: ['mautic-contacts'] });
|
|
2168
|
+
// Track the submission event
|
|
2169
|
+
if (variables.contact?.email) {
|
|
2170
|
+
const client = getMauticClient();
|
|
2171
|
+
client.trackEvent('form_submission', {
|
|
2172
|
+
formId: variables.formId,
|
|
2173
|
+
email: variables.contact.email
|
|
2174
|
+
}).catch(console.error);
|
|
2175
|
+
}
|
|
2176
|
+
},
|
|
2177
|
+
onError: (error) => {
|
|
2178
|
+
console.error('Mautic form submission failed:', error);
|
|
2179
|
+
},
|
|
2180
|
+
});
|
|
2181
|
+
};
|
|
2182
|
+
/**
|
|
2183
|
+
* Custom hook for creating Mautic contacts
|
|
2184
|
+
*/
|
|
2185
|
+
const useMauticCreateContact = () => {
|
|
2186
|
+
const queryClient = reactQuery.useQueryClient();
|
|
2187
|
+
return reactQuery.useMutation({
|
|
2188
|
+
mutationFn: (contact) => {
|
|
2189
|
+
const client = getMauticClient();
|
|
2190
|
+
return client.createContact(contact);
|
|
2191
|
+
},
|
|
2192
|
+
onSuccess: (data, variables) => {
|
|
2193
|
+
if (process.env.NODE_ENV === 'development') {
|
|
2194
|
+
console.log('Mautic contact created:', data);
|
|
2195
|
+
}
|
|
2196
|
+
// Invalidate contacts queries
|
|
2197
|
+
queryClient.invalidateQueries({ queryKey: ['mautic-contacts'] });
|
|
2198
|
+
queryClient.invalidateQueries({ queryKey: ['mautic-contact', variables.email] });
|
|
2199
|
+
},
|
|
2200
|
+
onError: (error) => {
|
|
2201
|
+
console.error('Failed to create Mautic contact:', error);
|
|
2202
|
+
},
|
|
2203
|
+
});
|
|
2204
|
+
};
|
|
2205
|
+
/**
|
|
2206
|
+
* Custom hook for updating Mautic contacts
|
|
2207
|
+
*/
|
|
2208
|
+
const useMauticUpdateContact = () => {
|
|
2209
|
+
const queryClient = reactQuery.useQueryClient();
|
|
2210
|
+
return reactQuery.useMutation({
|
|
2211
|
+
mutationFn: ({ contactId, contact }) => {
|
|
2212
|
+
const client = getMauticClient();
|
|
2213
|
+
return client.updateContact(contactId, contact);
|
|
2214
|
+
},
|
|
2215
|
+
onSuccess: (data, variables) => {
|
|
2216
|
+
if (process.env.NODE_ENV === 'development') {
|
|
2217
|
+
console.log('Mautic contact updated:', data);
|
|
2218
|
+
}
|
|
2219
|
+
// Invalidate related queries
|
|
2220
|
+
queryClient.invalidateQueries({ queryKey: ['mautic-contacts'] });
|
|
2221
|
+
queryClient.invalidateQueries({ queryKey: ['mautic-contact', variables.contactId] });
|
|
2222
|
+
},
|
|
2223
|
+
onError: (error) => {
|
|
2224
|
+
console.error('Failed to update Mautic contact:', error);
|
|
2225
|
+
},
|
|
2226
|
+
});
|
|
2227
|
+
};
|
|
2228
|
+
/**
|
|
2229
|
+
* Custom hook for fetching Mautic contact by email
|
|
2230
|
+
*/
|
|
2231
|
+
const useMauticContactByEmail = (email) => {
|
|
2232
|
+
return reactQuery.useQuery({
|
|
2233
|
+
queryKey: ['mautic-contact', email],
|
|
2234
|
+
queryFn: () => {
|
|
2235
|
+
const client = getMauticClient();
|
|
2236
|
+
return client.getContactByEmail(email);
|
|
2237
|
+
},
|
|
2238
|
+
enabled: !!email && email.includes('@'),
|
|
2239
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
2240
|
+
gcTime: 10 * 60 * 1000,
|
|
2241
|
+
});
|
|
2242
|
+
};
|
|
2243
|
+
/**
|
|
2244
|
+
* Custom hook for fetching Mautic forms
|
|
2245
|
+
*/
|
|
2246
|
+
const useMauticForms = () => {
|
|
2247
|
+
return reactQuery.useQuery({
|
|
2248
|
+
queryKey: ['mautic-forms'],
|
|
2249
|
+
queryFn: () => {
|
|
2250
|
+
const client = getMauticClient();
|
|
2251
|
+
return client.getForms();
|
|
2252
|
+
},
|
|
2253
|
+
staleTime: 30 * 60 * 1000, // Forms don't change often
|
|
2254
|
+
gcTime: 60 * 60 * 1000,
|
|
2255
|
+
});
|
|
2256
|
+
};
|
|
2257
|
+
/**
|
|
2258
|
+
* Custom hook for fetching a specific Mautic form
|
|
2259
|
+
*/
|
|
2260
|
+
const useMauticForm = (formId) => {
|
|
2261
|
+
return reactQuery.useQuery({
|
|
2262
|
+
queryKey: ['mautic-form', formId],
|
|
2263
|
+
queryFn: () => {
|
|
2264
|
+
const client = getMauticClient();
|
|
2265
|
+
return client.getForm(formId);
|
|
2266
|
+
},
|
|
2267
|
+
enabled: !!formId,
|
|
2268
|
+
staleTime: 30 * 60 * 1000,
|
|
2269
|
+
gcTime: 60 * 60 * 1000,
|
|
2270
|
+
});
|
|
2271
|
+
};
|
|
2272
|
+
/**
|
|
2273
|
+
* Custom hook for tracking Mautic events
|
|
2274
|
+
*/
|
|
2275
|
+
const useMauticEventTracking = () => {
|
|
2276
|
+
return reactQuery.useMutation({
|
|
2277
|
+
mutationFn: ({ email, eventName, eventData }) => {
|
|
2278
|
+
const client = getMauticClient();
|
|
2279
|
+
return client.trackEvent(eventName, {
|
|
2280
|
+
email,
|
|
2281
|
+
...(eventData || {})
|
|
2282
|
+
});
|
|
2283
|
+
},
|
|
2284
|
+
onSuccess: (data, variables) => {
|
|
2285
|
+
if (process.env.NODE_ENV === 'development') {
|
|
2286
|
+
console.log('Mautic event tracked successfully:', variables.eventName);
|
|
2287
|
+
}
|
|
2288
|
+
},
|
|
2289
|
+
onError: (error, variables) => {
|
|
2290
|
+
console.error('Failed to track Mautic event:', variables.eventName, error);
|
|
2291
|
+
},
|
|
2292
|
+
});
|
|
2293
|
+
};
|
|
2294
|
+
/**
|
|
2295
|
+
* Custom hook for adding tags to contacts
|
|
2296
|
+
*/
|
|
2297
|
+
const useMauticAddTags = () => {
|
|
2298
|
+
const queryClient = reactQuery.useQueryClient();
|
|
2299
|
+
return reactQuery.useMutation({
|
|
2300
|
+
mutationFn: ({ contactId, tags }) => {
|
|
2301
|
+
const client = getMauticClient();
|
|
2302
|
+
return client.addTagToContact(contactId, tags);
|
|
2303
|
+
},
|
|
2304
|
+
onSuccess: (data, variables) => {
|
|
2305
|
+
if (process.env.NODE_ENV === 'development') {
|
|
2306
|
+
console.log('Tags added to Mautic contact:', variables.tags);
|
|
2307
|
+
}
|
|
2308
|
+
// Invalidate contact queries
|
|
2309
|
+
queryClient.invalidateQueries({ queryKey: ['mautic-contact', variables.contactId] });
|
|
2310
|
+
},
|
|
2311
|
+
onError: (error) => {
|
|
2312
|
+
console.error('Failed to add tags to Mautic contact:', error);
|
|
2313
|
+
},
|
|
2314
|
+
});
|
|
2315
|
+
};
|
|
2316
|
+
/**
|
|
2317
|
+
* Custom hook for removing tags from contacts
|
|
2318
|
+
*/
|
|
2319
|
+
const useMauticRemoveTags = () => {
|
|
2320
|
+
const queryClient = reactQuery.useQueryClient();
|
|
2321
|
+
return reactQuery.useMutation({
|
|
2322
|
+
mutationFn: ({ contactId, tags }) => {
|
|
2323
|
+
const client = getMauticClient();
|
|
2324
|
+
return client.removeTagFromContact(contactId, tags);
|
|
2325
|
+
},
|
|
2326
|
+
onSuccess: (data, variables) => {
|
|
2327
|
+
if (process.env.NODE_ENV === 'development') {
|
|
2328
|
+
console.log('Tags removed from Mautic contact:', variables.tags);
|
|
2329
|
+
}
|
|
2330
|
+
// Invalidate contact queries
|
|
2331
|
+
queryClient.invalidateQueries({ queryKey: ['mautic-contact', variables.contactId] });
|
|
2332
|
+
},
|
|
2333
|
+
onError: (error) => {
|
|
2334
|
+
console.error('Failed to remove tags from Mautic contact:', error);
|
|
2335
|
+
},
|
|
2336
|
+
});
|
|
2337
|
+
};
|
|
2338
|
+
/**
|
|
2339
|
+
* Custom hook for getting contact tags
|
|
2340
|
+
*/
|
|
2341
|
+
const useMauticContactTags = (contactId) => {
|
|
2342
|
+
return reactQuery.useQuery({
|
|
2343
|
+
queryKey: ['mautic-contact-tags', contactId],
|
|
2344
|
+
queryFn: () => {
|
|
2345
|
+
const client = getMauticClient();
|
|
2346
|
+
return client.getContactTags(contactId);
|
|
2347
|
+
},
|
|
2348
|
+
enabled: !!contactId,
|
|
2349
|
+
staleTime: 5 * 60 * 1000,
|
|
2350
|
+
gcTime: 10 * 60 * 1000,
|
|
2351
|
+
});
|
|
2352
|
+
};
|
|
2353
|
+
/**
|
|
2354
|
+
* Custom hook for getting all tags
|
|
2355
|
+
*/
|
|
2356
|
+
const useMauticTags = () => {
|
|
2357
|
+
return reactQuery.useQuery({
|
|
2358
|
+
queryKey: ['mautic-tags'],
|
|
2359
|
+
queryFn: () => {
|
|
2360
|
+
const client = getMauticClient();
|
|
2361
|
+
return client.getTags();
|
|
2362
|
+
},
|
|
2363
|
+
staleTime: 30 * 60 * 1000,
|
|
2364
|
+
gcTime: 60 * 60 * 1000,
|
|
2365
|
+
});
|
|
2366
|
+
};
|
|
2367
|
+
/**
|
|
2368
|
+
* Custom hook for getting segments
|
|
2369
|
+
*/
|
|
2370
|
+
const useMauticSegments = () => {
|
|
2371
|
+
return reactQuery.useQuery({
|
|
2372
|
+
queryKey: ['mautic-segments'],
|
|
2373
|
+
queryFn: () => {
|
|
2374
|
+
const client = getMauticClient();
|
|
2375
|
+
return client.getSegments();
|
|
2376
|
+
},
|
|
2377
|
+
staleTime: 30 * 60 * 1000,
|
|
2378
|
+
gcTime: 60 * 60 * 1000,
|
|
2379
|
+
});
|
|
2380
|
+
};
|
|
2381
|
+
/**
|
|
2382
|
+
* Custom hook for adding contact to segment
|
|
2383
|
+
*/
|
|
2384
|
+
const useMauticAddToSegment = () => {
|
|
2385
|
+
const queryClient = reactQuery.useQueryClient();
|
|
2386
|
+
return reactQuery.useMutation({
|
|
2387
|
+
mutationFn: ({ contactId, segmentId }) => {
|
|
2388
|
+
const client = getMauticClient();
|
|
2389
|
+
return client.addContactToSegment(contactId, segmentId);
|
|
2390
|
+
},
|
|
2391
|
+
onSuccess: (data, variables) => {
|
|
2392
|
+
if (process.env.NODE_ENV === 'development') {
|
|
2393
|
+
console.log('Contact added to segment:', variables.segmentId);
|
|
2394
|
+
}
|
|
2395
|
+
// Invalidate contact queries
|
|
2396
|
+
queryClient.invalidateQueries({ queryKey: ['mautic-contact', variables.contactId] });
|
|
2397
|
+
},
|
|
2398
|
+
onError: (error) => {
|
|
2399
|
+
console.error('Failed to add contact to segment:', error);
|
|
2400
|
+
},
|
|
2401
|
+
});
|
|
2402
|
+
};
|
|
2403
|
+
/**
|
|
2404
|
+
* Custom hook for removing contact from segment
|
|
2405
|
+
*/
|
|
2406
|
+
const useMauticRemoveFromSegment = () => {
|
|
2407
|
+
const queryClient = reactQuery.useQueryClient();
|
|
2408
|
+
return reactQuery.useMutation({
|
|
2409
|
+
mutationFn: ({ contactId, segmentId }) => {
|
|
2410
|
+
const client = getMauticClient();
|
|
2411
|
+
return client.removeContactFromSegment(contactId, segmentId);
|
|
2412
|
+
},
|
|
2413
|
+
onSuccess: (data, variables) => {
|
|
2414
|
+
if (process.env.NODE_ENV === 'development') {
|
|
2415
|
+
console.log('Contact removed from segment:', variables.segmentId);
|
|
2416
|
+
}
|
|
2417
|
+
// Invalidate contact queries
|
|
2418
|
+
queryClient.invalidateQueries({ queryKey: ['mautic-contact', variables.contactId] });
|
|
2419
|
+
},
|
|
2420
|
+
onError: (error) => {
|
|
2421
|
+
console.error('Failed to remove contact from segment:', error);
|
|
2422
|
+
},
|
|
2423
|
+
});
|
|
2424
|
+
};
|
|
2425
|
+
|
|
2406
2426
|
const MauticForm = ({ formId, title, description, className = '', form, onSubmit, onSuccess, onError, }) => {
|
|
2407
2427
|
const [formData, setFormData] = React.useState({});
|
|
2408
2428
|
const [errors, setErrors] = React.useState({});
|
|
@@ -2575,21 +2595,19 @@ const MauticForm = ({ formId, title, description, className = '', form, onSubmit
|
|
|
2575
2595
|
.map((field) => (jsxRuntimeExports.jsxs("div", { className: `form-field form-field-${field.type}`, children: [field.showLabel !== false && (jsxRuntimeExports.jsxs("label", { htmlFor: field.alias, className: "field-label", children: [field.label, field.isRequired && jsxRuntimeExports.jsx("span", { className: "required", children: "*" })] })), renderField(field), field.properties?.helpText && (jsxRuntimeExports.jsx("p", { className: "field-help", children: field.properties.helpText })), errors[field.alias] && (jsxRuntimeExports.jsx("p", { className: "field-error", children: errors[field.alias] }))] }, field.id))) }), jsxRuntimeExports.jsx("div", { className: "form-actions", children: jsxRuntimeExports.jsx("button", { type: "submit", disabled: isSubmitting, className: "submit-button", children: isSubmitting ? 'Submitting...' : 'Submit' }) }), submitMutation.error && (jsxRuntimeExports.jsx("div", { className: "form-error", children: jsxRuntimeExports.jsx("p", { children: "There was an error submitting the form. Please try again." }) }))] }));
|
|
2576
2596
|
};
|
|
2577
2597
|
|
|
2578
|
-
const MauticTracking = ({ enabled, mauticUrl, proxyUrl,
|
|
2598
|
+
const MauticTracking = ({ enabled, mauticUrl, proxyUrl, children }) => {
|
|
2579
2599
|
React.useEffect(() => {
|
|
2580
2600
|
// Determine if tracking is enabled
|
|
2581
|
-
const isEnabled = enabled ??
|
|
2601
|
+
const isEnabled = enabled ?? !!proxyUrl;
|
|
2582
2602
|
const trackingProxyUrl = proxyUrl;
|
|
2583
2603
|
// Debug logging to understand configuration
|
|
2584
|
-
if (
|
|
2604
|
+
if (process.env.NODE_ENV === 'development') {
|
|
2585
2605
|
console.log('🔍 Mautic Tracking Debug:', {
|
|
2586
2606
|
isEnabled,
|
|
2587
2607
|
mauticUrl,
|
|
2588
2608
|
trackingProxyUrl,
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
isDev: undefined?.DEV,
|
|
2592
|
-
isProd: undefined?.PROD
|
|
2609
|
+
isDev: true,
|
|
2610
|
+
isProd: false
|
|
2593
2611
|
});
|
|
2594
2612
|
}
|
|
2595
2613
|
// Check if tracking is enabled
|
|
@@ -2598,7 +2616,7 @@ const MauticTracking = ({ enabled, mauticUrl, proxyUrl, appId, workerSecret, chi
|
|
|
2598
2616
|
return;
|
|
2599
2617
|
}
|
|
2600
2618
|
// Check if we're in development mode - skip tracking in dev
|
|
2601
|
-
if (
|
|
2619
|
+
if (process.env.NODE_ENV === 'development') {
|
|
2602
2620
|
console.log('Mautic tracking disabled in development mode');
|
|
2603
2621
|
return;
|
|
2604
2622
|
}
|
|
@@ -2609,6 +2627,8 @@ const MauticTracking = ({ enabled, mauticUrl, proxyUrl, appId, workerSecret, chi
|
|
|
2609
2627
|
}
|
|
2610
2628
|
console.log('✅ Mautic tracking enabled for production');
|
|
2611
2629
|
// Initialize Mautic tracking with error handling
|
|
2630
|
+
// Capture original fetch for cleanup
|
|
2631
|
+
let originalFetch;
|
|
2612
2632
|
try {
|
|
2613
2633
|
// Pre-initialize tracking object and queue (standard Mautic snippet behavior)
|
|
2614
2634
|
window.MauticTrackingObject = 'mt';
|
|
@@ -2616,20 +2636,12 @@ const MauticTracking = ({ enabled, mauticUrl, proxyUrl, appId, workerSecret, chi
|
|
|
2616
2636
|
(window.mt.q = window.mt.q || []).push(arguments);
|
|
2617
2637
|
};
|
|
2618
2638
|
// Intercept Mautic tracking API calls to use our proxy (generic /mtc/ matcher)
|
|
2619
|
-
|
|
2639
|
+
originalFetch = window.fetch.bind(window);
|
|
2620
2640
|
const interceptFetch = function (url, options) {
|
|
2621
2641
|
if (typeof url === 'string' && /\/mtc\//.test(url)) {
|
|
2622
2642
|
try {
|
|
2623
2643
|
const proxyUrl = url.replace(/https?:\/\/[^/]+\/mtc\//, `${trackingProxyUrl}?endpoint=/mtc/`);
|
|
2624
|
-
const proxyOptions = {
|
|
2625
|
-
...options,
|
|
2626
|
-
headers: {
|
|
2627
|
-
...options?.headers,
|
|
2628
|
-
'Content-Type': 'application/json',
|
|
2629
|
-
'x-app-id': appId || '',
|
|
2630
|
-
...(workerSecret ? { 'x-app-secret': workerSecret } : {})
|
|
2631
|
-
}
|
|
2632
|
-
};
|
|
2644
|
+
const proxyOptions = { ...options };
|
|
2633
2645
|
return originalFetch(proxyUrl, proxyOptions);
|
|
2634
2646
|
}
|
|
2635
2647
|
catch (e) {
|
|
@@ -2639,16 +2651,9 @@ const MauticTracking = ({ enabled, mauticUrl, proxyUrl, appId, workerSecret, chi
|
|
|
2639
2651
|
return originalFetch(url, options);
|
|
2640
2652
|
};
|
|
2641
2653
|
window.fetch = interceptFetch;
|
|
2642
|
-
// Fetch the tracking script through the proxy
|
|
2654
|
+
// Fetch the tracking script through the proxy
|
|
2643
2655
|
const trackingScriptUrl = `${trackingProxyUrl}?endpoint=/mtc.js`;
|
|
2644
|
-
fetch(trackingScriptUrl, {
|
|
2645
|
-
method: 'GET',
|
|
2646
|
-
headers: {
|
|
2647
|
-
'Content-Type': 'application/javascript',
|
|
2648
|
-
'x-app-id': appId || '',
|
|
2649
|
-
...(workerSecret ? { 'x-app-secret': workerSecret } : {})
|
|
2650
|
-
}
|
|
2651
|
-
})
|
|
2656
|
+
fetch(trackingScriptUrl, { method: 'GET' })
|
|
2652
2657
|
.then(response => {
|
|
2653
2658
|
if (!response.ok) {
|
|
2654
2659
|
throw new Error(`Failed to load Mautic tracking script: ${response.status}`);
|
|
@@ -2676,12 +2681,11 @@ const MauticTracking = ({ enabled, mauticUrl, proxyUrl, appId, workerSecret, chi
|
|
|
2676
2681
|
}
|
|
2677
2682
|
// Cleanup function
|
|
2678
2683
|
return () => {
|
|
2679
|
-
|
|
2680
|
-
if (window.fetch !== originalFetch) {
|
|
2684
|
+
if (originalFetch && window.fetch !== originalFetch) {
|
|
2681
2685
|
window.fetch = originalFetch;
|
|
2682
2686
|
}
|
|
2683
2687
|
};
|
|
2684
|
-
}, [enabled, mauticUrl, proxyUrl
|
|
2688
|
+
}, [enabled, mauticUrl, proxyUrl]);
|
|
2685
2689
|
// Render children if provided, otherwise render nothing
|
|
2686
2690
|
return children ? jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: children }) : null;
|
|
2687
2691
|
};
|
|
@@ -3056,30 +3060,33 @@ const validateField = (field, value) => {
|
|
|
3056
3060
|
const validateCustomRule = (rule, value, field) => {
|
|
3057
3061
|
switch (rule) {
|
|
3058
3062
|
case 'min_length':
|
|
3059
|
-
if (typeof value === 'string' && value.length < (field.properties?.minLength
|
|
3060
|
-
return `Minimum length is ${field.properties?.minLength} characters`;
|
|
3063
|
+
if (typeof value === 'string' && value.length < Number(field.properties?.minLength ?? 0)) {
|
|
3064
|
+
return `Minimum length is ${Number(field.properties?.minLength ?? 0)} characters`;
|
|
3061
3065
|
}
|
|
3062
3066
|
break;
|
|
3063
3067
|
case 'max_length':
|
|
3064
|
-
if (typeof value === 'string' && value.length > (field.properties?.maxLength
|
|
3065
|
-
return `Maximum length is ${field.properties?.maxLength} characters`;
|
|
3068
|
+
if (typeof value === 'string' && value.length > Number(field.properties?.maxLength ?? 1000)) {
|
|
3069
|
+
return `Maximum length is ${Number(field.properties?.maxLength ?? 1000)} characters`;
|
|
3066
3070
|
}
|
|
3067
3071
|
break;
|
|
3068
3072
|
case 'min_value':
|
|
3069
|
-
if (typeof value === 'number' && value < (field.properties?.minValue
|
|
3070
|
-
return `Minimum value is ${field.properties?.minValue}`;
|
|
3073
|
+
if (typeof value === 'number' && value < Number(field.properties?.minValue ?? 0)) {
|
|
3074
|
+
return `Minimum value is ${Number(field.properties?.minValue ?? 0)}`;
|
|
3071
3075
|
}
|
|
3072
3076
|
break;
|
|
3073
3077
|
case 'max_value':
|
|
3074
|
-
if (typeof value === 'number' && value > (field.properties?.maxValue
|
|
3075
|
-
return `Maximum value is ${field.properties?.maxValue}`;
|
|
3078
|
+
if (typeof value === 'number' && value > Number(field.properties?.maxValue ?? 1000000)) {
|
|
3079
|
+
return `Maximum value is ${Number(field.properties?.maxValue ?? 1000000)}`;
|
|
3076
3080
|
}
|
|
3077
3081
|
break;
|
|
3078
3082
|
case 'pattern':
|
|
3079
|
-
|
|
3080
|
-
const
|
|
3081
|
-
if (
|
|
3082
|
-
|
|
3083
|
+
{
|
|
3084
|
+
const pattern = field.properties?.pattern;
|
|
3085
|
+
if (pattern) {
|
|
3086
|
+
const regex = new RegExp(String(pattern));
|
|
3087
|
+
if (!regex.test(value)) {
|
|
3088
|
+
return 'Invalid format';
|
|
3089
|
+
}
|
|
3083
3090
|
}
|
|
3084
3091
|
}
|
|
3085
3092
|
break;
|
|
@@ -3169,7 +3176,6 @@ exports.isValidEmail = isValidEmail;
|
|
|
3169
3176
|
exports.isValidPhone = isValidPhone;
|
|
3170
3177
|
exports.isValidUrl = isValidUrl;
|
|
3171
3178
|
exports.loadMauticData = loadMauticData;
|
|
3172
|
-
exports.mauticService = mauticService;
|
|
3173
3179
|
exports.mergeMauticConfig = mergeMauticConfig;
|
|
3174
3180
|
exports.sanitizeFormData = sanitizeFormData;
|
|
3175
3181
|
exports.searchForms = searchForms;
|