astro-tractstack 2.3.5 → 2.4.1

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 (55) hide show
  1. package/bin/create-tractstack.js +38 -59
  2. package/dist/index.js +68 -36
  3. package/package.json +46 -9
  4. package/templates/custom/minimal/codehooks.ts +13 -0
  5. package/templates/custom/shopify/CartModal.tsx +11 -1
  6. package/templates/custom/shopify/CartReset.tsx +38 -0
  7. package/templates/custom/shopify/ShopifyCartManager.tsx +2 -0
  8. package/templates/custom/shopify/ShopifyProductGrid.tsx +4 -4
  9. package/templates/custom/shopify/ShopifyServiceList.tsx +56 -43
  10. package/templates/custom/shopify/cart-reset.astro +19 -0
  11. package/templates/custom/with-examples/codehooks.ts +15 -0
  12. package/templates/src/components/Header.astro +1 -1
  13. package/templates/src/components/codehooks/EpinetDurationSelector.tsx +38 -23
  14. package/templates/src/components/codehooks/EpinetTableView.tsx +5 -2
  15. package/templates/src/components/codehooks/EpinetWrapper.tsx +10 -5
  16. package/templates/src/components/codehooks/FeaturedArticle.astro +3 -3
  17. package/templates/src/components/codehooks/ListContent.astro +3 -3
  18. package/templates/src/components/compositor/Node.tsx +13 -2
  19. package/templates/src/components/compositor/nodes/Pane.tsx +2 -14
  20. package/templates/src/components/edit/pane/AddPanePanel.tsx +3 -2
  21. package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +35 -14
  22. package/templates/src/components/edit/pane/ConfigPanePanel.tsx +1 -1
  23. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +2 -2
  24. package/templates/src/components/storykeep/Dashboard_Analytics.tsx +8 -4
  25. package/templates/src/components/storykeep/controls/content/ContentBrowser.tsx +5 -2
  26. package/templates/src/components/storykeep/state/FetchAnalytics.tsx +8 -4
  27. package/templates/src/components/storykeep/widgets/Wizard.tsx +4 -2
  28. package/templates/src/lib/codeHookHelper.ts +156 -0
  29. package/templates/src/lib/resources.ts +41 -0
  30. package/templates/src/lib/storyData.ts +1 -2
  31. package/templates/src/pages/[...slug]/edit.astro +3 -3
  32. package/templates/src/pages/[...slug].astro +76 -70
  33. package/templates/src/pages/codehooks/[...hookId].astro +18 -0
  34. package/templates/src/pages/codehooks/bunny-video.astro +9 -0
  35. package/templates/src/pages/codehooks/custom-hero.astro +6 -0
  36. package/templates/src/pages/codehooks/epinet.astro +15 -0
  37. package/templates/src/pages/codehooks/featured-article.astro +13 -0
  38. package/templates/src/pages/codehooks/get-crafting.astro +8 -0
  39. package/templates/src/pages/codehooks/list-content.astro +13 -0
  40. package/templates/src/pages/codehooks/search-widget.astro +13 -0
  41. package/templates/src/pages/codehooks/shopify-product-grid.astro +23 -0
  42. package/templates/src/pages/codehooks/shopify-service-list.astro +23 -0
  43. package/templates/src/pages/context/[...contextSlug]/edit.astro +3 -3
  44. package/templates/src/pages/context/[...contextSlug].astro +47 -10
  45. package/templates/src/pages/sandbox.astro +3 -14
  46. package/templates/src/stores/analytics.ts +77 -107
  47. package/templates/src/stores/shopify.ts +34 -4
  48. package/utils/inject-files.ts +70 -37
  49. package/templates/custom/minimal/CodeHook.astro +0 -72
  50. package/templates/custom/with-examples/CodeHook.astro +0 -81
  51. package/templates/custom/with-examples/ProductCard.astro +0 -29
  52. package/templates/custom/with-examples/ProductCardWrapper.astro +0 -43
  53. package/templates/custom/with-examples/ProductGrid.astro +0 -64
  54. package/templates/src/components/codehooks/ProductCardSetup.tsx +0 -157
  55. package/templates/src/components/codehooks/ProductGridSetup.tsx +0 -279
@@ -0,0 +1,19 @@
1
+ ---
2
+ import Layout from '@/layouts/Layout.astro';
3
+ import CartReset from '@/custom/shopify/CartReset';
4
+ import { getBrandConfig } from '@/utils/api/brandConfig';
5
+
6
+ const tenantId =
7
+ Astro.locals.tenant?.id || import.meta.env.PUBLIC_TENANTID || 'default';
8
+
9
+ const brandConfig = await getBrandConfig(tenantId);
10
+ if (!brandConfig.HAS_SHOPIFY) {
11
+ return Astro.redirect('/storykeep');
12
+ }
13
+ ---
14
+
15
+ <Layout title="Reset Cart" slug="cart">
16
+ <main class="mx-auto max-w-7xl px-4 py-16 md:px-6 xl:px-8">
17
+ <CartReset client:only="react" />
18
+ </main>
19
+ </Layout>
@@ -0,0 +1,15 @@
1
+ // Static, hand-maintained per-install manifest of available codehook ids.
2
+ // The backend never sees this; it is a frontend build capability list only.
3
+ // To add/remove a hook, edit this array AND add/remove the matching blade at
4
+ // src/pages/codehooks/{id}.astro. Not regenerated automatically.
5
+ export const availableCodeHookIds: string[] = [
6
+ 'featured-article',
7
+ 'list-content',
8
+ 'search-widget',
9
+ 'bunny-video',
10
+ 'epinet',
11
+ 'shopify-product-grid',
12
+ 'shopify-service-list',
13
+ 'custom-hero',
14
+ 'get-crafting',
15
+ ];
@@ -141,7 +141,7 @@ if (hasShopify) {
141
141
  <div
142
142
  class="flex flex-row flex-nowrap justify-between bg-mywhite px-4 pb-3 pt-4 shadow-inner md:px-8"
143
143
  >
144
- <h1 class="truncate text-2xl text-mydarkgrey">{title}</h1>
144
+ <h1 id="page-title" class="truncate text-2xl text-mydarkgrey">{title}</h1>
145
145
  <div class="flex flex-row flex-nowrap items-center gap-x-2">
146
146
  {
147
147
  !isHome ? (
@@ -11,7 +11,10 @@ import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
11
11
  import CheckCircleIcon from '@heroicons/react/24/outline/CheckCircleIcon';
12
12
  import ChevronLeftIcon from '@heroicons/react/24/outline/ChevronLeftIcon';
13
13
  import ChevronRightIcon from '@heroicons/react/24/outline/ChevronRightIcon';
14
- import { epinetCustomFilters } from '@/stores/analytics';
14
+ import {
15
+ epinetCustomFilters,
16
+ setEpinetCustomFilters,
17
+ } from '@/stores/analytics';
15
18
  import EpinetTableView from './EpinetTableView';
16
19
  import { MAX_ANALYTICS_HOURS } from '@/constants';
17
20
  import type { AppliedFilter } from '@/stores/analytics';
@@ -220,7 +223,7 @@ const EpinetDurationSelector = ({
220
223
  }
221
224
  setIsApplying(true);
222
225
  try {
223
- epinetCustomFilters.set(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
226
+ setEpinetCustomFilters(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
224
227
  ...$epinetCustomFilters,
225
228
  visitorType: localFilters.visitorType,
226
229
  selectedUserId: localFilters.selectedUserId,
@@ -794,10 +797,16 @@ const EpinetDurationSelector = ({
794
797
  collection={createListCollection({
795
798
  items: [
796
799
  { value: '', label: 'Select user' },
797
- ...paginatedUserCounts.map((user) => ({
798
- value: user.id,
799
- label: `${user.id} (${user.count} events)`,
800
- })),
800
+ ...paginatedUserCounts.map(
801
+ (user: {
802
+ id: string;
803
+ count: number;
804
+ isKnown: boolean;
805
+ }) => ({
806
+ value: user.id,
807
+ label: `${user.id} (${user.count} events)`,
808
+ })
809
+ ),
801
810
  ],
802
811
  })}
803
812
  value={
@@ -844,23 +853,29 @@ const EpinetDurationSelector = ({
844
853
  Select user
845
854
  </Select.ItemText>
846
855
  </Select.Item>,
847
- ...paginatedUserCounts.map((user) => (
848
- <Select.Item
849
- key={user.id}
850
- item={{
851
- value: user.id,
852
- label: `${user.id} (${user.count} events)`,
853
- }}
854
- className="epinet-user-select-item cursor-pointer select-none p-2 text-sm text-gray-700 hover:bg-slate-100"
855
- >
856
- <Select.ItemText>
857
- {user.id}{' '}
858
- <span className="text-xs text-gray-500">
859
- ({user.count} events)
860
- </span>
861
- </Select.ItemText>
862
- </Select.Item>
863
- )),
856
+ ...paginatedUserCounts.map(
857
+ (user: {
858
+ id: string;
859
+ count: number;
860
+ isKnown: boolean;
861
+ }) => (
862
+ <Select.Item
863
+ key={user.id}
864
+ item={{
865
+ value: user.id,
866
+ label: `${user.id} (${user.count} events)`,
867
+ }}
868
+ className="epinet-user-select-item cursor-pointer select-none p-2 text-sm text-gray-700 hover:bg-slate-100"
869
+ >
870
+ <Select.ItemText>
871
+ {user.id}{' '}
872
+ <span className="text-xs text-gray-500">
873
+ ({user.count} events)
874
+ </span>
875
+ </Select.ItemText>
876
+ </Select.Item>
877
+ )
878
+ ),
864
879
  ]
865
880
  ) : (
866
881
  <div className="p-2 text-sm text-gray-500">
@@ -1,7 +1,10 @@
1
1
  import { useState, useEffect } from 'react';
2
2
  import { useStore } from '@nanostores/react';
3
3
  import { classNames } from '@/utils/helpers';
4
- import { epinetCustomFilters } from '@/stores/analytics';
4
+ import {
5
+ epinetCustomFilters,
6
+ setEpinetCustomFilters,
7
+ } from '@/stores/analytics';
5
8
  import { Accordion } from '@ark-ui/react';
6
9
  import ChevronLeftIcon from '@heroicons/react/24/outline/ChevronLeftIcon';
7
10
  import ChevronRightIcon from '@heroicons/react/24/outline/ChevronRightIcon';
@@ -176,7 +179,7 @@ const EpinetTableView = ({
176
179
  const endTimeUTC = new Date(
177
180
  Date.UTC(year, month - 1, day, hour, 59, 59, 999)
178
181
  );
179
- epinetCustomFilters.set(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
182
+ setEpinetCustomFilters(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
180
183
  ...$epinetCustomFilters,
181
184
  startTimeUTC: startTimeUTC.toISOString(),
182
185
  endTimeUTC: endTimeUTC.toISOString(),
@@ -6,7 +6,12 @@ import {
6
6
  type ReactNode,
7
7
  } from 'react';
8
8
  import { useStore } from '@nanostores/react';
9
- import { epinetCustomFilters, type AppliedFilter } from '@/stores/analytics';
9
+ import {
10
+ epinetCustomFilters,
11
+ getEpinetCustomFilters,
12
+ setEpinetCustomFilters,
13
+ type AppliedFilter,
14
+ } from '@/stores/analytics';
10
15
  import { TractStackAPI } from '@/utils/api';
11
16
  import SankeyDiagram from './SankeyDiagram';
12
17
  import EpinetDurationSelector from './EpinetDurationSelector';
@@ -97,7 +102,7 @@ const EpinetWrapper = ({
97
102
  useEffect(() => {
98
103
  const nowUTC = new Date();
99
104
  const oneWeekAgoUTC = new Date(nowUTC.getTime() - 7 * 24 * 60 * 60 * 1000);
100
- epinetCustomFilters.set(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
105
+ setEpinetCustomFilters(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
101
106
  enabled: true,
102
107
  visitorType: 'all',
103
108
  selectedUserId: null,
@@ -133,7 +138,7 @@ const EpinetWrapper = ({
133
138
 
134
139
  const handleBeliefFilterChange = (beliefSlug: string, value: string) => {
135
140
  const tenantId = window.TRACTSTACK_CONFIG?.tenantId || 'default';
136
- const currentFilters = epinetCustomFilters.get();
141
+ const currentFilters = getEpinetCustomFilters();
137
142
  let newFilters: AppliedFilter[] = [
138
143
  ...(currentFilters.appliedFilters || []),
139
144
  ];
@@ -151,7 +156,7 @@ const EpinetWrapper = ({
151
156
  }
152
157
  }
153
158
 
154
- epinetCustomFilters.set(tenantId, {
159
+ setEpinetCustomFilters(tenantId, {
155
160
  ...currentFilters,
156
161
  appliedFilters: newFilters,
157
162
  });
@@ -229,7 +234,7 @@ const EpinetWrapper = ({
229
234
  error: null,
230
235
  isLoading: false,
231
236
  });
232
- epinetCustomFilters.set(
237
+ setEpinetCustomFilters(
233
238
  window.TRACTSTACK_CONFIG?.tenantId || 'default',
234
239
  {
235
240
  ...$epinetCustomFilters,
@@ -7,10 +7,10 @@ export interface Props {
7
7
  options?: string;
8
8
  };
9
9
  };
10
- contentMap: FullContentMapItem[];
10
+ fullContentMap: FullContentMapItem[];
11
11
  }
12
12
 
13
- const { options, contentMap } = Astro.props;
13
+ const { options, fullContentMap } = Astro.props;
14
14
 
15
15
  let parsedOptions;
16
16
  try {
@@ -22,7 +22,7 @@ try {
22
22
 
23
23
  const slug = parsedOptions.slug || '';
24
24
 
25
- const featuredStory = contentMap.find(
25
+ const featuredStory = fullContentMap.find(
26
26
  (item: FullContentMapItem) =>
27
27
  item.slug === slug &&
28
28
  item.type === 'StoryFragment' &&
@@ -7,10 +7,10 @@ export interface Props {
7
7
  options?: string;
8
8
  };
9
9
  };
10
- contentMap: FullContentMapItem[];
10
+ fullContentMap: FullContentMapItem[];
11
11
  }
12
12
 
13
- const { options, contentMap } = Astro.props;
13
+ const { options, fullContentMap } = Astro.props;
14
14
 
15
15
  // Parse component options
16
16
  let parsedOptions;
@@ -36,7 +36,7 @@ const title = parsedOptions.title;
36
36
  const bgColor = parsedOptions.bgColor || '';
37
37
 
38
38
  // Filter for valid stories to display
39
- const validPages = contentMap.filter(
39
+ const validPages = fullContentMap.filter(
40
40
  (item: FullContentMapItem): boolean =>
41
41
  item.type === 'StoryFragment' &&
42
42
  typeof item.description === 'string' &&
@@ -149,6 +149,7 @@ export const Node = memo((props: NodeProps) => {
149
149
  first={true}
150
150
  ctx={ctx}
151
151
  isContextPane={true}
152
+ isSandboxMode={props.isSandboxMode || false}
152
153
  />
153
154
  </>
154
155
  );
@@ -201,7 +202,12 @@ export const Node = memo((props: NodeProps) => {
201
202
  element = (
202
203
  <>
203
204
  {first && (
204
- <AddPanePanel nodeId={props.nodeId} first={true} ctx={ctx} />
205
+ <AddPanePanel
206
+ nodeId={props.nodeId}
207
+ first={true}
208
+ ctx={ctx}
209
+ isSandboxMode={props.isSandboxMode || false}
210
+ />
205
211
  )}
206
212
  <div className="py-0.5">
207
213
  <ConfigPanePanel
@@ -217,7 +223,12 @@ export const Node = memo((props: NodeProps) => {
217
223
  {content}
218
224
  </PanelVisibilityWrapper>
219
225
  </div>
220
- <AddPanePanel nodeId={props.nodeId} first={false} ctx={ctx} />
226
+ <AddPanePanel
227
+ nodeId={props.nodeId}
228
+ first={false}
229
+ ctx={ctx}
230
+ isSandboxMode={props.isSandboxMode || false}
231
+ />
221
232
  </>
222
233
  );
223
234
  }
@@ -5,8 +5,6 @@ import { RenderChildren } from './RenderChildren';
5
5
  import FeaturedArticleSetup from '@/components/codehooks/FeaturedArticleSetup';
6
6
  import ListContentSetup from '@/components/codehooks/ListContentSetup';
7
7
  import BunnyVideoSetup from '@/components/codehooks/BunnyVideoSetup';
8
- import { ProductCardSetup } from '@/components/codehooks/ProductCardSetup';
9
- import { ProductGridSetup } from '@/components/codehooks/ProductGridSetup';
10
8
  import { PaneOverlay } from '@/components/compositor/tools/PaneOverlay';
11
9
  import type {
12
10
  PaneNode,
@@ -15,13 +13,7 @@ import type {
15
13
  } from '@/types/compositorTypes';
16
14
  import type { NodeProps } from '@/types/nodeProps';
17
15
 
18
- const TARGETS = [
19
- 'list-content',
20
- 'featured-article',
21
- 'bunny-video',
22
- 'product-card',
23
- 'product-grid',
24
- ];
16
+ const TARGETS = ['list-content', 'featured-article', 'bunny-video'];
25
17
 
26
18
  const CodeHookContainer = ({
27
19
  payload,
@@ -171,11 +163,7 @@ const Pane = memo(
171
163
  id={getCtx(props).getNodeSlug(props.nodeId)}
172
164
  className={useFlexLayout ? '' : wrapperClasses}
173
165
  >
174
- {codeHookPayload && codeHookTarget === 'product-card' ? (
175
- <ProductCardSetup nodeId={props.nodeId} params={codeHookParams} />
176
- ) : codeHookPayload && codeHookTarget === 'product-grid' ? (
177
- <ProductGridSetup nodeId={props.nodeId} params={codeHookParams} />
178
- ) : codeHookPayload && codeHookTarget === 'featured-article' ? (
166
+ {codeHookPayload && codeHookTarget === 'featured-article' ? (
179
167
  <FeaturedArticleSetup
180
168
  nodeId={props.nodeId}
181
169
  params={codeHookParams}
@@ -94,13 +94,14 @@ const AddPanePanel = ({
94
94
  />
95
95
  ) : mode === PaneAddMode.REUSE && !isContextPane ? (
96
96
  <AddPaneReUsePanel nodeId={nodeId} first={first} setMode={setMode} />
97
- ) : mode === PaneAddMode.CODEHOOK && !isContextPane ? (
97
+ ) : mode === PaneAddMode.CODEHOOK ? (
98
98
  <AddPaneCodeHookPanel
99
99
  nodeId={nodeId}
100
100
  first={first}
101
101
  setMode={setMode}
102
102
  isStoryFragment={isStoryFragment}
103
103
  isContextPane={isContextPane}
104
+ isSandboxMode={isSandboxMode}
104
105
  />
105
106
  ) : mode === PaneAddMode.PASTE ? (
106
107
  <AddPanePanel_paste
@@ -139,7 +140,7 @@ const AddPanePanel = ({
139
140
  )}
140
141
  </>
141
142
  )}
142
- {!isTemplate && !isContextPane && (
143
+ {!isTemplate && (
143
144
  <button
144
145
  onClick={() => setMode(PaneAddMode.CODEHOOK)}
145
146
  className="rounded bg-white px-2 py-1 text-sm text-cyan-700 shadow-sm transition-colors hover:bg-cyan-700 hover:text-white"
@@ -5,7 +5,11 @@ import { Combobox } from '@ark-ui/react';
5
5
  import { createListCollection } from '@ark-ui/react/collection';
6
6
  import ChevronUpDownIcon from '@heroicons/react/20/solid/ChevronUpDownIcon';
7
7
  import CheckIcon from '@heroicons/react/20/solid/CheckIcon';
8
- import { codehookMapStore, fullContentMapStore } from '@/stores/storykeep';
8
+ import {
9
+ brandConfigStore,
10
+ codehookMapStore,
11
+ fullContentMapStore,
12
+ } from '@/stores/storykeep';
9
13
  import { getCtx } from '@/stores/nodes';
10
14
  import { findUniqueSlug } from '@/utils/helpers';
11
15
  import { PaneAddMode, type TemplatePane } from '@/types/compositorTypes';
@@ -16,6 +20,7 @@ interface AddPaneCodeHookPanelProps {
16
20
  setMode: (mode: PaneAddMode) => void;
17
21
  isStoryFragment?: boolean;
18
22
  isContextPane?: boolean;
23
+ isSandboxMode?: boolean;
19
24
  }
20
25
 
21
26
  const AddPaneCodeHookPanel = ({
@@ -24,10 +29,13 @@ const AddPaneCodeHookPanel = ({
24
29
  setMode,
25
30
  isStoryFragment = false,
26
31
  isContextPane = false,
32
+ isSandboxMode = false,
27
33
  }: AddPaneCodeHookPanelProps) => {
28
34
  const [selected, setSelected] = useState<string | null>(null);
29
35
  const [query, setQuery] = useState('');
30
36
  const $contentMap = useStore(fullContentMapStore);
37
+ const brandConfig = useStore(brandConfigStore);
38
+ const hasShopify = brandConfig?.HAS_SHOPIFY === true;
31
39
 
32
40
  const existingSlugs = $contentMap
33
41
  .filter((item) => ['Pane', 'StoryFragment'].includes(item.type))
@@ -39,9 +47,22 @@ const AddPaneCodeHookPanel = ({
39
47
 
40
48
  const availableCodeHooks = codehookMapStore.get();
41
49
 
42
- // Filter hooks based on search query
50
+ const isHookVisibleInPicker = (hookName: string) => {
51
+ if (
52
+ (hookName === 'shopify-product-grid' ||
53
+ hookName === 'shopify-service-list') &&
54
+ !hasShopify
55
+ ) {
56
+ return false;
57
+ }
58
+ if (hookName === 'get-crafting' && !isSandboxMode) {
59
+ return false;
60
+ }
61
+ return true;
62
+ };
63
+
64
+ // Filter hooks based on search query and tenant/sandbox gates
43
65
  const filteredHooks = useMemo(() => {
44
- // Start with available hooks
45
66
  const hooks =
46
67
  query === ''
47
68
  ? [...availableCodeHooks]
@@ -49,9 +70,8 @@ const AddPaneCodeHookPanel = ({
49
70
  hook.toLowerCase().includes(query.toLowerCase())
50
71
  );
51
72
 
52
- // Create a new array with unavailable hooks removed (don't just filter - we want to show them as disabled)
53
- return hooks;
54
- }, [availableCodeHooks, query]);
73
+ return hooks.filter(isHookVisibleInPicker);
74
+ }, [availableCodeHooks, query, hasShopify, isSandboxMode]);
55
75
 
56
76
  // Create collection for Ark UI Combobox
57
77
  const collection = useMemo(() => {
@@ -64,21 +84,22 @@ const AddPaneCodeHookPanel = ({
64
84
 
65
85
  const isHookAvailable = (hookName: string) => {
66
86
  if (
67
- (hookName === 'featured-content' ||
68
- hookName === 'list-content' ||
69
- hookName === 'featured-article') &&
87
+ (hookName === 'list-content' || hookName === 'featured-article') &&
70
88
  !hasStoryFragments
71
89
  ) {
72
- return hasStoryFragments;
90
+ return false;
91
+ }
92
+ if (
93
+ hookName === 'bunny-video' &&
94
+ import.meta.env.PUBLIC_ENABLE_BUNNY !== 'true'
95
+ ) {
96
+ return false;
73
97
  }
74
98
  return true;
75
99
  };
76
100
 
77
101
  const getDisplayName = (hookName: string) => {
78
- if (
79
- (hookName === 'featured-content' || hookName === 'list-content') &&
80
- !hasStoryFragments
81
- ) {
102
+ if (hookName === 'list-content' && !hasStoryFragments) {
82
103
  return `${hookName} (not yet available; no pages found)`;
83
104
  }
84
105
  return hookName;
@@ -260,7 +260,7 @@ const ConfigPanePanel = ({
260
260
  )}
261
261
  </>
262
262
  )}
263
- {isCodeHook && !isContextPane && (
263
+ {isCodeHook && (
264
264
  <button
265
265
  onClick={handleCodeHookConfig}
266
266
  className={buttonClass}
@@ -13,7 +13,7 @@ import {
13
13
  type MenuNode,
14
14
  } from '@/types/compositorTypes';
15
15
  import MenuForm from '@/components/storykeep/controls/content/MenuForm';
16
- import { fullContentMapStore, getFullContentMap } from '@/stores/analytics';
16
+ import { getFullContentMap, setTenantFullContentMap } from '@/stores/analytics';
17
17
  import type { FullContentMapItem } from '@/types/tractstack';
18
18
 
19
19
  interface StoryFragmentMenuPanelProps {
@@ -53,7 +53,7 @@ const StoryFragmentMenuPanel = ({
53
53
  if (!contentMap) {
54
54
  const currentContentMap = await api.getContentMapWithTimestamp();
55
55
  if (currentContentMap.success && currentContentMap.data) {
56
- fullContentMapStore.set(tenantId, currentContentMap.data);
56
+ setTenantFullContentMap(tenantId, currentContentMap.data);
57
57
  setContentMap(currentContentMap.data.data);
58
58
  }
59
59
  }
@@ -1,7 +1,11 @@
1
1
  import { useState, useCallback, useMemo, Component } from 'react';
2
2
  import type { ReactNode } from 'react';
3
3
  import { useStore } from '@nanostores/react';
4
- import { epinetCustomFilters } from '@/stores/analytics';
4
+ import {
5
+ epinetCustomFilters,
6
+ getEpinetCustomFilters,
7
+ setEpinetCustomFilters,
8
+ } from '@/stores/analytics';
5
9
  import { classNames } from '@/utils/helpers';
6
10
  import ArrowDownTrayIcon from '@heroicons/react/24/outline/ArrowDownTrayIcon';
7
11
  import DashboardActivity from './Dashboard_Activity';
@@ -167,7 +171,7 @@ export default function StoryKeepDashboard_Analytics({
167
171
 
168
172
  const handleBeliefFilterChange = (beliefSlug: string, value: string) => {
169
173
  const tenantId = window.TRACTSTACK_CONFIG?.tenantId || 'default';
170
- const currentFilters = epinetCustomFilters.get();
174
+ const currentFilters = getEpinetCustomFilters();
171
175
  let newFilters = [...(currentFilters.appliedFilters || [])];
172
176
 
173
177
  if (value === 'All') {
@@ -183,7 +187,7 @@ export default function StoryKeepDashboard_Analytics({
183
187
  }
184
188
  }
185
189
 
186
- epinetCustomFilters.set(tenantId, {
190
+ setEpinetCustomFilters(tenantId, {
187
191
  ...currentFilters,
188
192
  appliedFilters: newFilters,
189
193
  });
@@ -220,7 +224,7 @@ export default function StoryKeepDashboard_Analytics({
220
224
  nowUTC.getTime() - hoursBack * 60 * 60 * 1000
221
225
  );
222
226
 
223
- epinetCustomFilters.set(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
227
+ setEpinetCustomFilters(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
224
228
  ...$epinetCustomFilters,
225
229
  enabled: true,
226
230
  startTimeUTC: startTimeUTC.toISOString(),
@@ -1,7 +1,10 @@
1
1
  import { useState, useEffect, useRef } from 'react';
2
2
  import { Switch } from '@ark-ui/react';
3
3
  import { useStore } from '@nanostores/react';
4
- import { epinetCustomFilters } from '@/stores/analytics';
4
+ import {
5
+ epinetCustomFilters,
6
+ setEpinetCustomFilters,
7
+ } from '@/stores/analytics';
5
8
  import { classNames } from '@/utils/helpers';
6
9
  import type { FullContentMapItem } from '@/types/tractstack';
7
10
 
@@ -104,7 +107,7 @@ const ContentBrowser = ({
104
107
  const setStandardDuration = (hours: number) => {
105
108
  const nowUTC = new Date();
106
109
  const startTimeUTC = new Date(nowUTC.getTime() - hours * 60 * 60 * 1000);
107
- epinetCustomFilters.set(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
110
+ setEpinetCustomFilters(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
108
111
  ...$epinetCustomFilters,
109
112
  enabled: true,
110
113
  startTimeUTC: startTimeUTC.toISOString(),
@@ -1,6 +1,10 @@
1
1
  import { useEffect, useRef } from 'react';
2
2
  import { useStore } from '@nanostores/react';
3
- import { epinetCustomFilters } from '@/stores/analytics';
3
+ import {
4
+ epinetCustomFilters,
5
+ getEpinetCustomFilters,
6
+ setEpinetCustomFilters,
7
+ } from '@/stores/analytics';
4
8
  import { TractStackAPI } from '@/utils/api';
5
9
 
6
10
  const VERBOSE = false;
@@ -252,7 +256,7 @@ class AnalyticsService {
252
256
  this.setCachedResponse(cacheKey, analyticsData);
253
257
  onUpdate(analyticsData);
254
258
 
255
- epinetCustomFilters.set(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
259
+ setEpinetCustomFilters(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
256
260
  ...filters,
257
261
  availableFilters: data.availableFilters || [],
258
262
  });
@@ -298,9 +302,9 @@ class AnalyticsService {
298
302
  if (VERBOSE) console.log('🏁 Initializing analytics filters');
299
303
  const nowUTC = new Date();
300
304
  const oneWeekAgoUTC = new Date(nowUTC.getTime() - 7 * 24 * 60 * 60 * 1000);
301
- const current = epinetCustomFilters.get();
305
+ const current = getEpinetCustomFilters();
302
306
  if (!current.enabled) {
303
- epinetCustomFilters.set(tenantId, {
307
+ setEpinetCustomFilters(tenantId, {
304
308
  enabled: true,
305
309
  visitorType: 'all',
306
310
  selectedUserId: null,
@@ -139,7 +139,7 @@ export default function Wizard({
139
139
  const buildWizardData = async () => {
140
140
  try {
141
141
  const homePage = activeContentMap.find(
142
- (item) => item.slug === homeSlug
142
+ (item: FullContentMapItem) => item.slug === homeSlug
143
143
  );
144
144
 
145
145
  let homeData = null;
@@ -173,7 +173,9 @@ export default function Wizard({
173
173
  hasPanes: !!homePage?.panes?.length,
174
174
  hasSeo: !!homePage?.description,
175
175
  hasMenu: !!homeData?.menuId,
176
- hasAnyMenu: activeContentMap.some((item) => item.type === 'Menu'),
176
+ hasAnyMenu: activeContentMap.some(
177
+ (item: FullContentMapItem) => item.type === 'Menu'
178
+ ),
177
179
  };
178
180
 
179
181
  setWizardData(data);