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