astro-tractstack 2.3.2 → 2.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/bin/create-tractstack.js +3 -3
  2. package/dist/index.js +33 -8
  3. package/package.json +1 -1
  4. package/templates/custom/shopify/Cart.tsx +83 -14
  5. package/templates/custom/shopify/CheckoutModal.tsx +192 -6
  6. package/templates/custom/shopify/ShopifyCartManager.tsx +53 -41
  7. package/templates/custom/shopify/cart.astro +7 -1
  8. package/templates/src/components/Header.astro +3 -1
  9. package/templates/src/components/form/advanced/APIConfigSection.tsx +219 -1
  10. package/templates/src/components/form/shopify/SchedulingSection.tsx +44 -0
  11. package/templates/src/components/storykeep/Dashboard_Advanced.tsx +10 -1
  12. package/templates/src/components/storykeep/Dashboard_Shopify.tsx +9 -0
  13. package/templates/src/components/storykeep/controls/content/ManageContent.tsx +1 -0
  14. package/templates/src/components/storykeep/controls/content/ResourceForm.tsx +80 -0
  15. package/templates/src/components/storykeep/shopify/ShopifyDashboard_Bookings.tsx +86 -8
  16. package/templates/src/constants.ts +2 -0
  17. package/templates/src/pages/api/google/oauth/callback.ts +50 -0
  18. package/templates/src/pages/api/google/oauth/disconnect.ts +32 -0
  19. package/templates/src/pages/api/google/oauth/start.ts +32 -0
  20. package/templates/src/pages/api/google/oauth/status.ts +32 -0
  21. package/templates/src/pages/privacy.astro +84 -0
  22. package/templates/src/pages/terms.astro +47 -0
  23. package/templates/src/stores/shopify.ts +5 -0
  24. package/templates/src/types/tractstack.ts +30 -0
  25. package/templates/src/utils/api/advancedHelpers.ts +16 -0
  26. package/templates/src/utils/api/bookingHelpers.ts +3 -1
  27. package/templates/src/utils/api/brandHelpers.ts +8 -1
  28. package/templates/src/utils/booking/appointmentMode.ts +135 -0
  29. package/templates/src/utils/customHelpers.ts +2 -0
  30. package/utils/inject-files.ts +29 -4
  31. package/templates/src/components/codehooks/SandboxAuthWrapper.tsx +0 -101
  32. package/templates/src/utils/actions/actionButton.ts +0 -103
  33. package/templates/src/utils/actions/preParse_Clicked.ts +0 -87
@@ -1,101 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
- import { Dialog } from '@ark-ui/react/dialog';
3
- import { Portal } from '@ark-ui/react/portal';
4
- import XMarkIcon from '@heroicons/react/24/solid/XMarkIcon';
5
- import { ProfileStorage } from '@/utils/profileStorage';
6
- import SandboxRegisterForm from '@/components/codehooks/SandboxRegisterForm';
7
-
8
- interface SandboxAuthWrapperProps {
9
- isServerSideAuthenticated: boolean;
10
- }
11
-
12
- export default function SandboxAuthWrapper({
13
- isServerSideAuthenticated,
14
- }: SandboxAuthWrapperProps) {
15
- const [profileExists, setProfileExists] = useState<boolean | null>(null);
16
-
17
- useEffect(() => {
18
- const hasLocalProfile = ProfileStorage.hasProfile();
19
-
20
- if (hasLocalProfile && !isServerSideAuthenticated) {
21
- const token = localStorage.getItem('tractstack_profile_token');
22
-
23
- if (token) {
24
- ProfileStorage.storeProfileToken(token);
25
- window.location.reload();
26
- return;
27
- } else {
28
- ProfileStorage.clearProfile();
29
- setProfileExists(false);
30
- }
31
- } else {
32
- setProfileExists(hasLocalProfile);
33
- }
34
- }, [isServerSideAuthenticated]);
35
-
36
- const handleRegistrationSuccess = () => {
37
- setProfileExists(true);
38
- window.location.reload();
39
- };
40
-
41
- const handleClose = () => {
42
- window.location.href = '/';
43
- };
44
-
45
- if (profileExists === true && isServerSideAuthenticated) {
46
- return null;
47
- }
48
-
49
- if (profileExists === null) {
50
- return null;
51
- }
52
-
53
- return (
54
- <Dialog.Root open={true} modal={true} trapFocus={false}>
55
- <Portal>
56
- <Dialog.Backdrop
57
- className="fixed inset-0 bg-black bg-opacity-75"
58
- style={{ zIndex: 9005 }}
59
- />
60
- <Dialog.Positioner
61
- className="fixed inset-0 flex items-center justify-center p-4"
62
- style={{ zIndex: 9005 }}
63
- >
64
- <Dialog.Content className="relative grid w-full max-w-6xl grid-cols-1 overflow-hidden rounded-lg bg-white shadow-2xl md:grid-cols-2">
65
- <button
66
- onClick={handleClose}
67
- className="absolute right-4 top-4 z-10 rounded-full bg-gray-100 p-2 text-gray-600 shadow-sm transition-colors hover:bg-gray-200"
68
- title="Close and exit Sandbox"
69
- >
70
- <XMarkIcon className="h-5 w-5" />
71
- </button>
72
-
73
- <div className="flex flex-col justify-center bg-gray-50 p-8 text-right">
74
- <h2 className="text-4xl font-bold text-gray-900 md:text-5xl">
75
- Press <span className="italic text-blue-600">your own</span>{' '}
76
- Tract Stack
77
- </h2>
78
- <p className="mt-4 text-lg text-gray-600">
79
- Create an interactive webpage in a sandbox! No credit card
80
- required.
81
- </p>
82
- <p className="mt-8 text-sm text-gray-500">
83
- Already connected?{' '}
84
- <a
85
- href="/storykeep/profile"
86
- className="font-bold text-blue-600 underline hover:text-blue-500"
87
- >
88
- Unlock your profile
89
- </a>
90
- </p>
91
- </div>
92
-
93
- <div className="flex flex-col justify-center p-8">
94
- <SandboxRegisterForm onSuccess={handleRegistrationSuccess} />
95
- </div>
96
- </Dialog.Content>
97
- </Dialog.Positioner>
98
- </Portal>
99
- </Dialog.Root>
100
- );
101
- }
@@ -1,103 +0,0 @@
1
- import { preParseClicked } from './preParse_Clicked';
2
- import type { BrandConfig } from '@/types/tractstack';
3
-
4
- interface ActionButtonParams {
5
- callbackPayload: any;
6
- targetUrl: string;
7
- paneId: string;
8
- config: BrandConfig;
9
- }
10
-
11
- // Import the sendAnalyticsEvent function to send events to backend
12
- async function sendAnalyticsEvent(event: {
13
- contentId: string;
14
- contentType: 'Pane' | 'StoryFragment';
15
- eventVerb: string;
16
- duration?: number;
17
- }): Promise<void> {
18
- try {
19
- const config = window.TRACTSTACK_CONFIG;
20
- if (!config || !config.sessionId) return;
21
- const backendUrl =
22
- import.meta.env.PUBLIC_GO_BACKEND || 'http://localhost:8080';
23
-
24
- const sessionId = config.sessionId;
25
- const formData: { [key: string]: string } = {
26
- beliefId: event.contentId,
27
- beliefType: event.contentType,
28
- beliefValue: event.eventVerb,
29
- paneId: '',
30
- };
31
-
32
- if (event.duration !== undefined) {
33
- formData.duration = event.duration.toString();
34
- }
35
-
36
- await fetch(`${backendUrl}/api/v1/state`, {
37
- method: 'POST',
38
- headers: {
39
- 'Content-Type': 'application/x-www-form-urlencoded',
40
- 'X-Tenant-ID': config.tenantId,
41
- 'X-TractStack-Session-ID': sessionId,
42
- 'X-StoryFragment-ID': config.storyfragmentId,
43
- },
44
- body: new URLSearchParams(formData),
45
- });
46
- } catch (error) {
47
- console.error('⛔ API ERROR: Analytics event failed', error, event);
48
- }
49
- }
50
-
51
- export function handleActionButtonClick({
52
- callbackPayload,
53
- targetUrl,
54
- paneId,
55
- config,
56
- }: ActionButtonParams): void {
57
- const event = preParseClicked(paneId, callbackPayload, config);
58
-
59
- if (event) {
60
- console.log(event);
61
- sendAnalyticsEvent({
62
- contentId: event.targetId || event.targetSlug || event.id,
63
- contentType: 'Pane',
64
- eventVerb: event.verb,
65
- });
66
- }
67
-
68
- // Handle URL navigation and scroll
69
- if (targetUrl.startsWith('#') || targetUrl.includes('#')) {
70
- const id = targetUrl.split('#')[1];
71
- const element = document.getElementById(id);
72
-
73
- if (element) {
74
- // Calculate the target position
75
- const elementRect = element.getBoundingClientRect();
76
- const targetPosition = elementRect.top + window.scrollY;
77
-
78
- // Perform smooth scroll
79
- window.scrollTo({
80
- top: targetPosition,
81
- behavior: 'smooth',
82
- });
83
-
84
- // After scrolling, ensure the page layout is preserved
85
- const checkScrollEnd = setInterval(() => {
86
- if (
87
- window.scrollY === targetPosition ||
88
- Math.abs(window.scrollY - targetPosition) < 2
89
- ) {
90
- clearInterval(checkScrollEnd);
91
- document.body.style.minHeight = `${Math.max(
92
- document.body.scrollHeight,
93
- document.documentElement.scrollHeight
94
- )}px`;
95
- }
96
- }, 100);
97
- } else {
98
- window.location.href = targetUrl;
99
- }
100
- } else {
101
- window.location.href = targetUrl;
102
- }
103
- }
@@ -1,87 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import type { BrandConfig } from '@/types/tractstack';
3
-
4
- export const preParseClicked = (
5
- id: string,
6
- payload: any,
7
- config: BrandConfig
8
- ) => {
9
- const thisPayload = (payload && payload[0]) || false;
10
-
11
- if (!thisPayload || !config?.HOME_SLUG) {
12
- return null;
13
- }
14
-
15
- const command = (thisPayload && thisPayload[0] && thisPayload[0][0]) || null;
16
- const parameters =
17
- (thisPayload && thisPayload[0] && thisPayload[0][1]) || null;
18
-
19
- if (command === 'bunnyMoment' && parameters) {
20
- const videoId = parameters[0];
21
- return {
22
- id: id,
23
- type: `StartVideoMoment`,
24
- verb: `WATCHED`,
25
- targetId: videoId || null,
26
- };
27
- }
28
-
29
- if (command === `goto` && parameters) {
30
- const parameterOne = parameters[0] || null;
31
- const parameterTwo = parameters[1] || null;
32
- //const parameterThree = parameters[2] || null;
33
-
34
- switch (parameterOne) {
35
- case `home`:
36
- return {
37
- id: id,
38
- type: `PaneClicked`,
39
- verb: `CLICKED`,
40
- targetSlug: config?.HOME_SLUG,
41
- };
42
-
43
- case `storyFragment`:
44
- case `storyFragmentPane`:
45
- return {
46
- id: id,
47
- type: `PaneClicked`,
48
- verb: `CLICKED`,
49
- targetSlug: parameterTwo,
50
- };
51
-
52
- case `bunny`:
53
- return {
54
- id: id,
55
- type: `StartVideo`,
56
- verb: `WATCHED`,
57
- targetSlug: parameterTwo,
58
- };
59
-
60
- case `sandbox`:
61
- return {
62
- id: id,
63
- type: `SandboxAction`,
64
- verb: `CLICKED`,
65
- targetSlug: parameterTwo || 'main',
66
- };
67
-
68
- case `storykeep`:
69
- case `context`:
70
- case `concierge`:
71
- case `product`:
72
- case `url`:
73
- // ignore these
74
- break;
75
-
76
- default:
77
- console.log(
78
- `LispActionPayload preParseEvent misfire`,
79
- command,
80
- parameters
81
- );
82
- break;
83
- }
84
- }
85
-
86
- return null;
87
- };