astro-tractstack 2.3.0 → 2.3.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 (63) hide show
  1. package/README.md +1 -1
  2. package/bin/create-tractstack.js +2 -2
  3. package/dist/index.js +94 -16
  4. package/package.json +2 -2
  5. package/templates/custom/minimal/CodeHook.astro +10 -2
  6. package/templates/custom/shopify/Cart.tsx +100 -73
  7. package/templates/custom/shopify/CheckoutModal.tsx +509 -120
  8. package/templates/custom/shopify/NativeBookingCalendar.tsx +375 -0
  9. package/templates/custom/shopify/ShopifyCartManager.tsx +92 -37
  10. package/templates/custom/shopify/ShopifyProductGrid.tsx +139 -173
  11. package/templates/custom/shopify/ShopifyServiceList.tsx +20 -3
  12. package/templates/custom/with-examples/CodeHook.astro +10 -2
  13. package/templates/src/components/Footer.astro +4 -4
  14. package/templates/src/components/Header.astro +9 -3
  15. package/templates/src/components/edit/pane/AddPanePanel_new.tsx +3 -3
  16. package/templates/src/components/edit/pane/AiRestylePaneModal.tsx +2 -2
  17. package/templates/src/components/edit/pane/steps/AiCreativeDesignStep.tsx +2 -2
  18. package/templates/src/components/edit/pane/steps/AiLibraryCopyStep.tsx +3 -3
  19. package/templates/src/components/edit/pane/steps/AiRefineDesignStep.tsx +2 -2
  20. package/templates/src/components/edit/pane/steps/AiStandardDesignStep.tsx +7 -7
  21. package/templates/src/components/form/advanced/APIConfigSection.tsx +244 -2
  22. package/templates/src/components/form/shopify/SchedulingSection.tsx +354 -0
  23. package/templates/src/components/storykeep/Dashboard.tsx +1 -1
  24. package/templates/src/components/storykeep/Dashboard_Shopify.tsx +253 -110
  25. package/templates/src/components/storykeep/controls/content/BeliefTable.tsx +14 -5
  26. package/templates/src/components/storykeep/controls/content/KnownResourceTable.tsx +5 -2
  27. package/templates/src/components/storykeep/controls/content/MenuTable.tsx +14 -5
  28. package/templates/src/components/storykeep/controls/content/ProductTable.tsx +180 -101
  29. package/templates/src/components/storykeep/controls/content/ResourceBulkIngest.tsx +9 -5
  30. package/templates/src/components/storykeep/controls/content/ResourceTable.tsx +13 -4
  31. package/templates/src/components/storykeep/controls/content/StoryFragmentTable.tsx +14 -5
  32. package/templates/src/components/storykeep/shopify/ShopifyDashboard.tsx +111 -0
  33. package/templates/src/components/storykeep/shopify/ShopifyDashboard_Bookings.tsx +393 -0
  34. package/templates/src/components/storykeep/shopify/ShopifyDashboard_Products.tsx +46 -0
  35. package/templates/src/components/storykeep/shopify/ShopifyDashboard_Schedule.tsx +78 -0
  36. package/templates/src/components/storykeep/shopify/ShopifyDashboard_Search.tsx +55 -0
  37. package/templates/src/components/storykeep/shopify/ShopifyDashboard_Services.tsx +47 -0
  38. package/templates/src/pages/api/auth/lookup-lead.ts +72 -0
  39. package/templates/src/pages/api/booking/availability.ts +72 -0
  40. package/templates/src/pages/api/booking/cancel.ts +73 -0
  41. package/templates/src/pages/api/booking/confirm.ts +82 -0
  42. package/templates/src/pages/api/booking/hold.ts +75 -0
  43. package/templates/src/pages/api/booking/list.ts +66 -0
  44. package/templates/src/pages/api/booking/metrics.ts +60 -0
  45. package/templates/src/pages/api/booking/release.ts +76 -0
  46. package/templates/src/pages/api/sandbox.ts +2 -2
  47. package/templates/src/pages/api/shopify/createCart.ts +4 -8
  48. package/templates/src/pages/api/shopify/getProducts.ts +15 -15
  49. package/templates/src/pages/storykeep/login.astro +21 -14
  50. package/templates/src/stores/shopify.ts +81 -25
  51. package/templates/src/types/tractstack.ts +54 -0
  52. package/templates/src/utils/api/advancedConfig.ts +2 -0
  53. package/templates/src/utils/api/advancedHelpers.ts +40 -3
  54. package/templates/src/utils/api/bookingHelpers.ts +125 -0
  55. package/templates/src/utils/api/brandHelpers.ts +10 -0
  56. package/templates/src/utils/auth.ts +29 -9
  57. package/templates/src/utils/compositor/aiGeneration.ts +3 -3
  58. package/templates/src/utils/compositor/aiPaneParser.ts +2 -2
  59. package/templates/src/utils/customHelpers.ts +0 -21
  60. package/templates/src/utils/profileStorage.ts +5 -0
  61. package/templates/src/utils/tenantResolver.ts +2 -1
  62. package/utils/inject-files.ts +82 -4
  63. package/templates/custom/shopify/CalDotComBooking.tsx +0 -44
@@ -4,7 +4,7 @@ import {
4
4
  parseAiPane,
5
5
  createDefaultShell,
6
6
  } from '@/utils/compositor/aiPaneParser';
7
- import { callAskLemurAPI } from '@/utils/compositor/aiGeneration';
7
+ import { callAaiAPI } from '@/utils/compositor/aiGeneration';
8
8
  import { markdownToHtml } from '@/utils/compositor/htmlAst';
9
9
  import { CopyInputStep, type CopyMode } from './CopyInputStep';
10
10
  import { AiDesignStep, type AiDesignConfig } from './AiDesignStep';
@@ -148,7 +148,7 @@ export const AiStandardDesignStep = ({
148
148
  let shellResult = '';
149
149
 
150
150
  if (isAiStyling) {
151
- // AI Path: Generate Shell via AskLemur
151
+ // AI Path: Generate Shell via Aai
152
152
  let designInput = `Generate a design using a **${aiDesignConfig.harmony.toLowerCase()}** color scheme with a **${aiDesignConfig.theme.toLowerCase()}** theme.`;
153
153
  if (aiDesignConfig.baseColor)
154
154
  designInput += ` Base the colors around **${aiDesignConfig.baseColor}**.`;
@@ -173,7 +173,7 @@ export const AiStandardDesignStep = ({
173
173
  );
174
174
  }
175
175
 
176
- shellResult = await callAskLemurAPI({
176
+ shellResult = await callAaiAPI({
177
177
  prompt: formattedShellPrompt,
178
178
  context: masterShellSystem,
179
179
  expectJson: true,
@@ -204,7 +204,7 @@ export const AiStandardDesignStep = ({
204
204
  .replace('{{LAYOUT_TYPE}}', layoutType)
205
205
  .replace('{{SHELL_JSON}}', shellResult);
206
206
 
207
- finalHtml = await callAskLemurAPI({
207
+ finalHtml = await callAaiAPI({
208
208
  prompt: formattedCopyPrompt,
209
209
  context: masterCopySystem,
210
210
  expectJson: false,
@@ -218,7 +218,7 @@ export const AiStandardDesignStep = ({
218
218
  .replace('{{SHELL_JSON}}', shellResult)
219
219
  .replace('{{COPY_INPUT}}', copyValue);
220
220
 
221
- finalHtml = await callAskLemurAPI({
221
+ finalHtml = await callAaiAPI({
222
222
  prompt: formattedStylePrompt,
223
223
  context: masterStyleSystem,
224
224
  expectJson: false,
@@ -246,7 +246,7 @@ export const AiStandardDesignStep = ({
246
246
  .replace('{{SHELL_JSON}}', shellResult)
247
247
  .replace('{{COPY_INPUT}}', content);
248
248
 
249
- const styledHtml = await callAskLemurAPI({
249
+ const styledHtml = await callAaiAPI({
250
250
  prompt: formattedStylePrompt,
251
251
  context: masterStyleSystem,
252
252
  expectJson: false,
@@ -289,7 +289,7 @@ export const AiStandardDesignStep = ({
289
289
  .replace('{{LAYOUT_TYPE}}', layoutType)
290
290
  .replace('{{COLUMN_EXAMPLE}}', columnPreset.example);
291
291
 
292
- const copyResult = await callAskLemurAPI({
292
+ const copyResult = await callAaiAPI({
293
293
  prompt: formattedCopyPrompt,
294
294
  context: masterCopySystem,
295
295
  expectJson: false,
@@ -1,4 +1,7 @@
1
+ import { useState } from 'react';
2
+ import { Dialog, Portal } from '@ark-ui/react';
1
3
  import StringInput from '../StringInput';
4
+ import BooleanToggle from '../BooleanToggle';
2
5
  import type { FormStateReturn } from '@/hooks/useFormState';
3
6
  import type {
4
7
  AdvancedConfigState,
@@ -16,13 +19,18 @@ export default function APIConfigSection({
16
19
  }: APIConfigSectionProps) {
17
20
  const { state, updateField, errors } = formState;
18
21
 
22
+ const [isModalOpen, setIsModalOpen] = useState(false);
23
+ const goBackend =
24
+ import.meta.env.PUBLIC_GO_BACKEND || 'http://localhost:8080';
25
+
19
26
  // Status flags
20
27
  const aaiConfigured = status?.aaiAPIKeySet;
21
28
  const shopifyStorefrontConfigured = status?.shopifyStorefrontTokenSet;
22
29
  const shopifySecretConfigured = status?.shopifyApiSecretSet;
23
30
  const shopifyDomainConfigured = status?.shopifyStoreDomainSet;
24
31
  const shopifyVersionConfigured = Boolean(status?.shopifyApiVersion);
25
-
32
+ const shopifyAdminSlugConfigured = status?.shopifyAdminSlugSet;
33
+ const shopifyWebhooksConfigured = status?.userSetupWebhooks;
26
34
  const resendConfigured = status?.resendApiKeySet;
27
35
 
28
36
  const renderStatusBadge = (isConfigured: boolean | undefined) => {
@@ -92,7 +100,9 @@ export default function APIConfigSection({
92
100
  shopifyStorefrontConfigured &&
93
101
  shopifySecretConfigured &&
94
102
  shopifyDomainConfigured &&
95
- shopifyVersionConfigured
103
+ shopifyVersionConfigured &&
104
+ shopifyAdminSlugConfigured &&
105
+ shopifyWebhooksConfigured
96
106
  )}
97
107
  </div>
98
108
  <div className="space-y-4">
@@ -113,6 +123,20 @@ export default function APIConfigSection({
113
123
  </p>
114
124
  </div>
115
125
 
126
+ <div>
127
+ <StringInput
128
+ label="Shopify Admin Slug"
129
+ value={state.shopifyAdminSlug}
130
+ onChange={(value) => updateField('shopifyAdminSlug', value)}
131
+ placeholder="your-store-slug"
132
+ error={errors.shopifyAdminSlug}
133
+ />
134
+ <p className="mt-1 text-xs text-gray-500">
135
+ The internal Shopify slug (found in
136
+ admin.shopify.com/store/SLUG).
137
+ </p>
138
+ </div>
139
+
116
140
  <div>
117
141
  <StringInput
118
142
  label="API Version"
@@ -165,6 +189,37 @@ export default function APIConfigSection({
165
189
  {shopifySecretConfigured && ' Leave blank to keep existing.'}
166
190
  </p>
167
191
  </div>
192
+
193
+ {!shopifyWebhooksConfigured && (
194
+ <div className="mt-6 border-t border-gray-100 pt-6">
195
+ <div className="mb-4 rounded-md border border-amber-200 bg-amber-50 p-4">
196
+ <h5 className="text-sm font-bold text-amber-800">
197
+ Webhook Configuration Required
198
+ </h5>
199
+ <p className="mb-3 mt-1 text-xs text-amber-700">
200
+ To ensure synchronization between Shopify and the
201
+ TractStack native booking system, you must configure
202
+ webhook subscriptions within your Shopify Admin panel.
203
+ </p>
204
+ <button
205
+ onClick={() => setIsModalOpen(true)}
206
+ className="text-xs font-bold text-amber-900 underline hover:text-amber-700"
207
+ type="button"
208
+ >
209
+ [ Detailed Instructions ]
210
+ </button>
211
+ </div>
212
+
213
+ <BooleanToggle
214
+ label="Webhooks Manually Configured"
215
+ description="I have manually created the required webhooks (orders/paid, products/*) in my Shopify Admin."
216
+ value={state.userSetupWebhooks}
217
+ onChange={(value) =>
218
+ updateField('userSetupWebhooks', value)
219
+ }
220
+ />
221
+ </div>
222
+ )}
168
223
  </div>
169
224
  </div>
170
225
 
@@ -191,6 +246,193 @@ export default function APIConfigSection({
191
246
  </div>
192
247
  </div>
193
248
  </div>
249
+
250
+ <Dialog.Root
251
+ open={isModalOpen}
252
+ onOpenChange={(details) => setIsModalOpen(details.open)}
253
+ preventScroll={true}
254
+ lazyMount
255
+ unmountOnExit
256
+ >
257
+ <Portal>
258
+ <Dialog.Backdrop className="fixed inset-0 z-50 bg-black bg-opacity-75" />
259
+ <Dialog.Positioner className="fixed inset-0 z-50 flex items-center justify-center p-4">
260
+ <Dialog.Content
261
+ className="relative flex w-full max-w-2xl flex-col overflow-hidden rounded-lg bg-white shadow-xl"
262
+ style={{ maxHeight: '90vh' }}
263
+ >
264
+ {/* Header - Fixed height */}
265
+ <div className="flex items-center justify-between border-b border-gray-200 px-6 py-4">
266
+ <Dialog.Title className="text-xl font-bold text-gray-900">
267
+ How to Configure Webhooks in Shopify
268
+ </Dialog.Title>
269
+ <Dialog.CloseTrigger asChild>
270
+ <button
271
+ className="text-gray-400 hover:text-gray-600"
272
+ type="button"
273
+ >
274
+ <span className="text-2xl">&times;</span>
275
+ </button>
276
+ </Dialog.CloseTrigger>
277
+ </div>
278
+
279
+ {/* Body - Scrollable via flex-1 */}
280
+ <div className="flex-1 overflow-y-auto p-6 text-sm text-gray-700">
281
+ <ol className="mb-6 list-decimal space-y-2 pl-5">
282
+ <li>Log in to your Shopify Admin dashboard.</li>
283
+ <li>
284
+ Click on <strong>Settings</strong> (the gear icon) in the
285
+ bottom left corner.
286
+ </li>
287
+ <li>
288
+ In the left sidebar, select <strong>Notifications</strong>.
289
+ </li>
290
+ <li>
291
+ Scroll all the way to the bottom to the{' '}
292
+ <strong>Webhooks</strong> section.
293
+ </li>
294
+ <li>
295
+ Click the <strong>Create webhook</strong> button.
296
+ </li>
297
+ <li>
298
+ For each required webhook (listed below), configure the
299
+ following settings:
300
+ <ul className="mt-2 list-disc space-y-1 pl-5">
301
+ <li>
302
+ <strong>Event:</strong> Select the specific event (e.g.,
303
+ Order payment, Product creation).
304
+ </li>
305
+ <li>
306
+ <strong>Format:</strong> Select JSON (TractStack relies
307
+ on JSON unmarshaling).
308
+ </li>
309
+ <li>
310
+ <strong>URL:</strong> Enter your backend webhook URL:{' '}
311
+ <code className="rounded bg-gray-100 px-1 py-0.5 text-xs">
312
+ {goBackend}/api/v1/hooks/shopify
313
+ </code>
314
+ </li>
315
+ <li>
316
+ <strong>Webhook API version:</strong> Select the version
317
+ that matches your ShopifyAPIVersion configured in
318
+ TractStack.
319
+ </li>
320
+ </ul>
321
+ </li>
322
+ <li>
323
+ Click <strong>Save</strong>.
324
+ </li>
325
+ </ol>
326
+
327
+ <div className="mb-6 border-l-4 border-red-500 bg-red-50 p-4">
328
+ <p className="font-bold text-red-800">CRITICAL:</p>
329
+ <p className="mt-1 text-red-700">
330
+ After saving your first webhook, Shopify will display a{' '}
331
+ <strong>Webhook signing secret</strong> at the bottom of the
332
+ Webhooks section. You must copy this secret and add it to
333
+ your TractStack API Config as the Shopify API Secret. The
334
+ backend uses this to verify the HMAC signature of all
335
+ incoming payloads.
336
+ </p>
337
+ </div>
338
+
339
+ <h4 className="mb-3 text-lg font-bold">
340
+ Required Webhooks Breakdown
341
+ </h4>
342
+ <p className="mb-4">
343
+ You must create a separate webhook subscription for each of
344
+ the following four topics. All of them should point to the
345
+ exact same URL:{' '}
346
+ <code className="rounded bg-gray-100 px-1 py-0.5 text-xs">
347
+ {goBackend}/api/v1/hooks/shopify
348
+ </code>
349
+ </p>
350
+
351
+ <div className="space-y-4">
352
+ <div className="rounded border border-gray-200 bg-gray-50 p-4">
353
+ <h5 className="font-bold">1. Order Paid</h5>
354
+ <ul className="mt-2 space-y-1 text-xs">
355
+ <li>
356
+ <span className="font-bold text-gray-900">
357
+ Shopify Event Name:
358
+ </span>{' '}
359
+ Order payment
360
+ </li>
361
+ <li>
362
+ <span className="font-bold text-gray-900">
363
+ Topic Header:
364
+ </span>{' '}
365
+ orders/paid
366
+ </li>
367
+ <li>
368
+ <span className="font-bold text-gray-900">
369
+ Purpose:
370
+ </span>{' '}
371
+ Transitions the corresponding hold in the bookings
372
+ database table from PENDING to CONFIRMED.
373
+ </li>
374
+ </ul>
375
+ </div>
376
+
377
+ <div className="rounded border border-gray-200 bg-gray-50 p-4">
378
+ <h5 className="font-bold">2. Product Creation</h5>
379
+ <ul className="mt-2 space-y-1 text-xs">
380
+ <li>
381
+ <span className="font-bold text-gray-900">
382
+ Shopify Event Name:
383
+ </span>{' '}
384
+ Product creation
385
+ </li>
386
+ <li>
387
+ <span className="font-bold text-gray-900">
388
+ Topic Header:
389
+ </span>{' '}
390
+ products/create
391
+ </li>
392
+ </ul>
393
+ </div>
394
+
395
+ <div className="rounded border border-gray-200 bg-gray-50 p-4">
396
+ <h5 className="font-bold">3. Product Update</h5>
397
+ <ul className="mt-2 space-y-1 text-xs">
398
+ <li>
399
+ <span className="font-bold text-gray-900">
400
+ Shopify Event Name:
401
+ </span>{' '}
402
+ Product update
403
+ </li>
404
+ <li>
405
+ <span className="font-bold text-gray-900">
406
+ Topic Header:
407
+ </span>{' '}
408
+ products/update
409
+ </li>
410
+ </ul>
411
+ </div>
412
+
413
+ <div className="rounded border border-gray-200 bg-gray-50 p-4">
414
+ <h5 className="font-bold">4. Product Deletion</h5>
415
+ <ul className="mt-2 space-y-1 text-xs">
416
+ <li>
417
+ <span className="font-bold text-gray-900">
418
+ Shopify Event Name:
419
+ </span>{' '}
420
+ Product deletion
421
+ </li>
422
+ <li>
423
+ <span className="font-bold text-gray-900">
424
+ Topic Header:
425
+ </span>{' '}
426
+ products/delete
427
+ </li>
428
+ </ul>
429
+ </div>
430
+ </div>
431
+ </div>
432
+ </Dialog.Content>
433
+ </Dialog.Positioner>
434
+ </Portal>
435
+ </Dialog.Root>
194
436
  </div>
195
437
  );
196
438
  }