@aglyn/plugins-commerce 1.0.0-beta.234 → 1.0.0-beta.236

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 (135) hide show
  1. package/package.json +13 -13
  2. package/src/lib/components/cart.js +3 -2
  3. package/src/lib/components/cart.js.map +1 -1
  4. package/src/lib/components/console/commerce-analytics-card.component.js +3 -6
  5. package/src/lib/components/console/commerce-analytics-card.component.js.map +1 -1
  6. package/src/lib/components/console/commerce-glance-card.component.js +9 -3
  7. package/src/lib/components/console/commerce-glance-card.component.js.map +1 -1
  8. package/src/lib/components/console/customer-notifications-card.component.js +3 -1
  9. package/src/lib/components/console/customer-notifications-card.component.js.map +1 -1
  10. package/src/lib/components/console/discounts-card.component.js +2 -3
  11. package/src/lib/components/console/discounts-card.component.js.map +1 -1
  12. package/src/lib/components/console/host-coupons-card.component.js +3 -4
  13. package/src/lib/components/console/host-coupons-card.component.js.map +1 -1
  14. package/src/lib/components/console/local-delivery-settings-card.component.js +2 -2
  15. package/src/lib/components/console/local-delivery-settings-card.component.js.map +1 -1
  16. package/src/lib/components/console/locations-card.component.js +1 -1
  17. package/src/lib/components/console/locations-card.component.js.map +1 -1
  18. package/src/lib/components/console/member-posts-card.component.js +2 -2
  19. package/src/lib/components/console/member-posts-card.component.js.map +1 -1
  20. package/src/lib/components/console/order-detail-dialog.component.js +35 -30
  21. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  22. package/src/lib/components/console/order-fulfillment-panel.component.d.ts +11 -1
  23. package/src/lib/components/console/order-fulfillment-panel.component.js +75 -4
  24. package/src/lib/components/console/order-fulfillment-panel.component.js.map +1 -1
  25. package/src/lib/components/console/order-zones.d.ts +45 -1
  26. package/src/lib/components/console/order-zones.js +8 -0
  27. package/src/lib/components/console/order-zones.js.map +1 -1
  28. package/src/lib/components/console/pickup-delivery-queue-card.component.js +15 -1
  29. package/src/lib/components/console/pickup-delivery-queue-card.component.js.map +1 -1
  30. package/src/lib/components/console/pos-page.component.js +3 -2
  31. package/src/lib/components/console/pos-page.component.js.map +1 -1
  32. package/src/lib/components/console/product-editor-dialog.component.d.ts +2 -0
  33. package/src/lib/components/console/product-editor-dialog.component.js +30 -12
  34. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
  35. package/src/lib/components/console/products-hub-card.component.js +13 -4
  36. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  37. package/src/lib/components/console/products-hub-zone.component.d.ts +2 -1
  38. package/src/lib/components/console/products-hub-zone.component.js +1 -1
  39. package/src/lib/components/console/products-hub-zone.component.js.map +1 -1
  40. package/src/lib/components/console/reviews-moderation-card.component.js +1 -2
  41. package/src/lib/components/console/reviews-moderation-card.component.js.map +1 -1
  42. package/src/lib/components/console/shipping-settings-card.component.js +2 -2
  43. package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
  44. package/src/lib/components/console/shippingeasy-card.component.js +1 -1
  45. package/src/lib/components/console/shippingeasy-card.component.js.map +1 -1
  46. package/src/lib/components/console/shipstation-card.component.js +1 -2
  47. package/src/lib/components/console/shipstation-card.component.js.map +1 -1
  48. package/src/lib/components/console/store-settings-card.component.js +3 -1
  49. package/src/lib/components/console/store-settings-card.component.js.map +1 -1
  50. package/src/lib/components/console/tax-settings-card.component.js +4 -1
  51. package/src/lib/components/console/tax-settings-card.component.js.map +1 -1
  52. package/src/lib/components/order-status.js +24 -1
  53. package/src/lib/components/order-status.js.map +1 -1
  54. package/src/lib/components/product-detail.js +30 -16
  55. package/src/lib/components/product-detail.js.map +1 -1
  56. package/src/lib/components/product-grid.d.ts +7 -0
  57. package/src/lib/components/product-grid.js +50 -7
  58. package/src/lib/components/product-grid.js.map +1 -1
  59. package/src/lib/components/related-products.js +1 -1
  60. package/src/lib/components/related-products.js.map +1 -1
  61. package/src/lib/components/wishlist.js +1 -1
  62. package/src/lib/components/wishlist.js.map +1 -1
  63. package/src/lib/declarations.server.js +11 -0
  64. package/src/lib/declarations.server.js.map +1 -1
  65. package/src/lib/model/commerce-orders.d.ts +8 -0
  66. package/src/lib/model/commerce-orders.js.map +1 -1
  67. package/src/lib/model/commerce.d.ts +21 -0
  68. package/src/lib/model/commerce.js +39 -1
  69. package/src/lib/model/commerce.js.map +1 -1
  70. package/src/lib/model/index.d.ts +1 -0
  71. package/src/lib/model/index.js +1 -0
  72. package/src/lib/model/index.js.map +1 -1
  73. package/src/lib/model/order-annotations.d.ts +54 -0
  74. package/src/lib/model/order-annotations.js +76 -0
  75. package/src/lib/model/order-annotations.js.map +1 -0
  76. package/src/lib/model/order-events.d.ts +2 -0
  77. package/src/lib/model/order-events.js.map +1 -1
  78. package/src/lib/model/order-fulfillment.d.ts +29 -0
  79. package/src/lib/model/order-fulfillment.js +63 -0
  80. package/src/lib/model/order-fulfillment.js.map +1 -1
  81. package/src/lib/model/order-local-fulfillment.d.ts +36 -0
  82. package/src/lib/model/order-local-fulfillment.js +19 -1
  83. package/src/lib/model/order-local-fulfillment.js.map +1 -1
  84. package/src/lib/model/order-status-view.d.ts +11 -0
  85. package/src/lib/model/order-status-view.js +20 -3
  86. package/src/lib/model/order-status-view.js.map +1 -1
  87. package/src/lib/model/product-write.js +8 -4
  88. package/src/lib/model/product-write.js.map +1 -1
  89. package/src/lib/server/api-v1/openapi.js +1 -0
  90. package/src/lib/server/api-v1/openapi.js.map +1 -1
  91. package/src/lib/server/api-v1/order-view.d.ts +1 -0
  92. package/src/lib/server/api-v1/order-view.js +10 -0
  93. package/src/lib/server/api-v1/order-view.js.map +1 -1
  94. package/src/lib/server/cart-checkout.js +9 -1
  95. package/src/lib/server/cart-checkout.js.map +1 -1
  96. package/src/lib/server/catalog.d.ts +6 -0
  97. package/src/lib/server/catalog.js +3 -1
  98. package/src/lib/server/catalog.js.map +1 -1
  99. package/src/lib/server/checkout.js +11 -1
  100. package/src/lib/server/checkout.js.map +1 -1
  101. package/src/lib/server/fulfill-order.d.ts +12 -0
  102. package/src/lib/server/fulfill-order.js +13 -0
  103. package/src/lib/server/fulfill-order.js.map +1 -1
  104. package/src/lib/server/local-delivery-records.d.ts +30 -0
  105. package/src/lib/server/local-delivery-records.js +284 -0
  106. package/src/lib/server/local-delivery-records.js.map +1 -0
  107. package/src/lib/server/order-annotations.d.ts +28 -0
  108. package/src/lib/server/order-annotations.js +143 -0
  109. package/src/lib/server/order-annotations.js.map +1 -0
  110. package/src/lib/server/order-events.js +2 -1
  111. package/src/lib/server/order-events.js.map +1 -1
  112. package/src/lib/server/order-notifications.js +39 -8
  113. package/src/lib/server/order-notifications.js.map +1 -1
  114. package/src/lib/server/pos-payment.js +9 -3
  115. package/src/lib/server/pos-payment.js.map +1 -1
  116. package/src/lib/server/product-catalog.js +6 -2
  117. package/src/lib/server/product-catalog.js.map +1 -1
  118. package/src/lib/server/product-drafts.d.ts +36 -9
  119. package/src/lib/server/product-drafts.js +24 -5
  120. package/src/lib/server/product-drafts.js.map +1 -1
  121. package/src/lib/server/product.d.ts +6 -1
  122. package/src/lib/server/product.js +1 -1
  123. package/src/lib/server/product.js.map +1 -1
  124. package/src/lib/server/products-write.d.ts +29 -0
  125. package/src/lib/server/products-write.js +7 -7
  126. package/src/lib/server/products-write.js.map +1 -1
  127. package/src/lib/server/shipment-records.js +2 -0
  128. package/src/lib/server/shipment-records.js.map +1 -1
  129. package/src/lib/server/site-page-resolver.d.ts +13 -0
  130. package/src/lib/server/site-page-resolver.js +138 -1
  131. package/src/lib/server/site-page-resolver.js.map +1 -1
  132. package/src/lib/server.js +5 -0
  133. package/src/lib/server.js.map +1 -1
  134. package/src/lib/utils/use-storefront-purchase-event.js +8 -2
  135. package/src/lib/utils/use-storefront-purchase-event.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/store-settings-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n Button,\n FormControlLabel,\n MenuItem,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport { doc } from 'firebase/firestore'\nimport { useCallback, useState } from 'react'\nimport { useFirestore, useUser } from '@aglyn/tenant-feature-instance'\nimport {\n useFirestoreDoc,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { writeSiteWideChange } from '@aglyn/tenant-feature-instance/hooks/helpers/site-wide-change'\n\nexport interface StoreSettingsCardProps {\n hostId: string\n}\n\ninterface StoreSettings {\n /** Screen rendered for /products/{slug} with product tokens (AGL-292). */\n pdpScreenId?: string\n /** Screen rendered for /collections/{slug} (AGL-298). */\n collectionScreenId?: string\n currency?: string\n guestCheckout?: boolean\n termsUrl?: string\n receiptFooter?: string\n}\n\n/**\n * Store settings (AGL-295) on `hosts/{hostId}/settings/store`: the PDP\n * template screen (drives /products/{slug}), currency display, checkout\n * preferences, and receipt branding. Tax and shipping have their own\n * cards; store password/maintenance live in Site Protection.\n */\nexport function StoreSettingsCard(props: StoreSettingsCardProps) {\n const { hostId } = props\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const {\n data: store,\n status: storeStatus,\n /**\n * The settings doc this form is seeded from is unconfirmed by the server\n * (AGL-1358). `current` is `draft ?? {…store}` and the save writes all\n * six keys, so `merge: true` protects only the tax and shipping maps that\n * belong to other cards — never this card's own fields. Against a cached\n * read, changing the currency rewrites `guestCheckout`, and the two\n * template ids fall back to `|| null`, which is how a storefront's\n * product and collection URLs start returning 404.\n */\n fromCache: storeFromCache,\n } = useFirestoreDoc<any>(\n () => doc(firestore, 'hosts', hostId, 'settings', 'store'),\n [firestore, hostId],\n )\n const { data: host } = useFirestoreDoc<any>(\n () => doc(firestore, 'hosts', hostId),\n [firestore, hostId],\n )\n const [draft, setDraft] = useState<StoreSettings | null>(null)\n const current: StoreSettings = draft ?? {\n pdpScreenId: store?.pdpScreenId ?? '',\n collectionScreenId: store?.collectionScreenId ?? '',\n currency: store?.currency ?? 'USD',\n guestCheckout: store?.guestCheckout !== false,\n termsUrl: store?.termsUrl ?? '',\n receiptFooter: store?.receiptFooter ?? '',\n }\n const update = (patch: Partial<StoreSettings>) =>\n setDraft({ ...current, ...patch })\n\n // Host screen directory: {screenId: path} (AGL-292 template pick).\n const screenEntries = Object.entries(\n (host?.screens ?? {}) as Record<string, string>,\n ).sort(([, a], [, b]) => String(a).localeCompare(String(b)))\n\n const handleSave = useCallback(async () => {\n /**\n * Refuse a save whose seed the server never confirmed (AGL-1358).\n *\n * There is no create path to exempt, and that is deliberate rather than\n * an oversight: unlike a new row at a fresh uid, this writes a FIXED\n * document path, so the all-defaults `current` produced when the cache\n * has never seen this doc is not the harmless blank a fresh uid would\n * be. It would put `USD`, guest checkout on and two null template ids\n * over whatever the server really holds.\n *\n * The guard WRAPS the write — an early return is a shape you can keep\n * while losing the protection.\n */\n const verdict = await writeGuardedBySeed(\n {\n subject: 'store settings',\n unreadable: storeStatus === 'error',\n fromCache: storeFromCache,\n },\n async () => {\n // The product and collection templates, the currency and the\n // checkout rules render on the live store with no publish step, so\n // the save carries the site's cache drop with it.\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.set(\n doc(firestore, 'hosts', hostId, 'settings', 'store'),\n {\n pdpScreenId: current.pdpScreenId || null,\n collectionScreenId: current.collectionScreenId || null,\n currency: current.currency ?? 'USD',\n guestCheckout: current.guestCheckout !== false,\n termsUrl: current.termsUrl || null,\n receiptFooter: current.receiptFooter || null,\n },\n { merge: true },\n ),\n })\n },\n )\n // Before `setDraft(null)`, so a refusal keeps every typed value on\n // screen. A save that silently does nothing sends the user back to\n // retype a form that will be refused again just as quietly.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n setDraft(null)\n enqueueSnackbar('Store settings saved', {\n variant: 'success',\n persist: false,\n })\n }, [\n current,\n firestore,\n hostId,\n user,\n enqueueSnackbar,\n storeStatus,\n storeFromCache,\n ])\n\n return (\n <CardDisplay\n header={'Store settings'}\n help={pluginDocsHelp('commerce')}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1.5}>\n <TextField\n label=\"Product page template\"\n value={current.pdpScreenId ?? ''}\n onChange={(event) => update({ pdpScreenId: event.target.value })}\n size=\"small\"\n select\n helperText={\n 'Page rendered at /products/{slug} — design it in the ' +\n 'Besigner with the Product detail block and {{product.*}} tokens.'\n }\n >\n <MenuItem value=\"\">{'None (product URLs 404)'}</MenuItem>\n {screenEntries.map(([screenId, path]) => (\n <MenuItem key={screenId} value={screenId}>\n {`/${path === '/' ? '' : path}`}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n label=\"Collection page template\"\n value={current.collectionScreenId ?? ''}\n onChange={(event) =>\n update({ collectionScreenId: event.target.value })\n }\n size=\"small\"\n select\n helperText={\n 'Page rendered at /collections/{slug} — drop a Product grid ' +\n 'with source \"A collection\" and {{collection.*}} tokens.'\n }\n >\n <MenuItem value=\"\">{'None (collection URLs 404)'}</MenuItem>\n {screenEntries.map(([screenId, path]) => (\n <MenuItem key={screenId} value={screenId}>\n {`/${path === '/' ? '' : path}`}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n label=\"Currency\"\n value={current.currency ?? 'USD'}\n onChange={(event) => update({ currency: event.target.value })}\n size=\"small\"\n select\n sx={{ maxWidth: 200 }}\n helperText=\"Charges settle in USD; more currencies are coming\"\n >\n <MenuItem value=\"USD\">{'USD ($)'}</MenuItem>\n </TextField>\n <FormControlLabel\n control={\n <Switch\n size=\"small\"\n checked={current.guestCheckout !== false}\n onChange={(event) =>\n update({ guestCheckout: event.target.checked })\n }\n />\n }\n label=\"Allow guest checkout (no account required)\"\n />\n <TextField\n label=\"Terms URL\"\n value={current.termsUrl ?? ''}\n onChange={(event) => update({ termsUrl: event.target.value })}\n size=\"small\"\n placeholder=\"/terms\"\n helperText=\"Linked from checkout when set\"\n />\n <TextField\n label=\"Receipt footer\"\n value={current.receiptFooter ?? ''}\n onChange={(event) => update({ receiptFooter: event.target.value })}\n size=\"small\"\n multiline\n minRows={2}\n placeholder=\"Thanks for supporting our shop!\"\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Password protection and maintenance mode live under Site ' +\n 'Protection.'}\n </Typography>\n <Button\n variant=\"contained\"\n color=\"primary\"\n size=\"small\"\n disabled={!draft}\n onClick={handleSave}\n sx={{ alignSelf: 'flex-start' }}\n >\n {'Save store settings'}\n </Button>\n </Stack>\n </CardDisplay>\n )\n}\nStoreSettingsCard.displayName = 'StoreSettingsCard'\n\nexport default StoreSettingsCard\n"],"names":["CardDisplay","useSnackbar","Button","FormControlLabel","MenuItem","Stack","Switch","TextField","Typography","doc","useCallback","useState","useFirestore","useUser","useFirestoreDoc","writeGuardedBySeed","pluginDocsHelp","writeSiteWideChange","StoreSettingsCard","props","current","hostId","firestore","data","user","enqueueSnackbar","store","status","storeStatus","fromCache","storeFromCache","host","draft","setDraft","pdpScreenId","collectionScreenId","currency","guestCheckout","termsUrl","receiptFooter","update","patch","screenEntries","Object","entries","screens","sort","a","b","String","localeCompare","handleSave","verdict","subject","unreadable","write","batch","set","merge","ok","message","variant","persist","header","help","contentGutterX","contentGutterY","spacing","label","value","onChange","event","target","size","select","helperText","map","screenId","path","sx","maxWidth","control","checked","placeholder","multiline","minRows","color","disabled","onClick","alignSelf","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/store-settings-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n Button,\n FormControlLabel,\n MenuItem,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport { doc } from 'firebase/firestore'\nimport { useCallback, useState } from 'react'\nimport { useFirestore, useUser } from '@aglyn/tenant-feature-instance'\nimport {\n useFirestoreDoc,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { writeSiteWideChange } from '@aglyn/tenant-feature-instance/hooks/helpers/site-wide-change'\n\nexport interface StoreSettingsCardProps {\n hostId: string\n}\n\ninterface StoreSettings {\n /** Screen rendered for /products/{slug} with product tokens (AGL-292). */\n pdpScreenId?: string\n /** Screen rendered for /collections/{slug} (AGL-298). */\n collectionScreenId?: string\n currency?: string\n guestCheckout?: boolean\n termsUrl?: string\n receiptFooter?: string\n}\n\n/**\n * Store settings (AGL-295) on `hosts/{hostId}/settings/store`: the PDP\n * template screen (drives /products/{slug}), currency display, checkout\n * preferences, and receipt branding. Tax and shipping have their own\n * cards; store password/maintenance live in Site Protection.\n */\nexport function StoreSettingsCard(props: StoreSettingsCardProps) {\n const { hostId } = props\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const {\n data: store,\n status: storeStatus,\n /**\n * The settings doc this form is seeded from is unconfirmed by the server\n * (AGL-1358). `current` is `draft ?? {…store}` and the save writes all\n * six keys, so `merge: true` protects only the tax and shipping maps that\n * belong to other cards — never this card's own fields. Against a cached\n * read, changing the currency rewrites `guestCheckout`, and the two\n * template ids fall back to `|| null`, which is how a storefront's\n * product and collection URLs start returning 404.\n */\n fromCache: storeFromCache,\n } = useFirestoreDoc<any>(\n () => doc(firestore, 'hosts', hostId, 'settings', 'store'),\n [firestore, hostId],\n )\n const { data: host } = useFirestoreDoc<any>(\n () => doc(firestore, 'hosts', hostId),\n [firestore, hostId],\n )\n const [draft, setDraft] = useState<StoreSettings | null>(null)\n const current: StoreSettings = draft ?? {\n pdpScreenId: store?.pdpScreenId ?? '',\n collectionScreenId: store?.collectionScreenId ?? '',\n currency: store?.currency ?? 'USD',\n guestCheckout: store?.guestCheckout !== false,\n termsUrl: store?.termsUrl ?? '',\n receiptFooter: store?.receiptFooter ?? '',\n }\n const update = (patch: Partial<StoreSettings>) =>\n setDraft({ ...current, ...patch })\n\n // Host screen directory: {screenId: path} (AGL-292 template pick).\n const screenEntries = Object.entries(\n (host?.screens ?? {}) as Record<string, string>,\n ).sort(([, a], [, b]) => String(a).localeCompare(String(b)))\n\n const handleSave = useCallback(async () => {\n /**\n * Refuse a save whose seed the server never confirmed (AGL-1358).\n *\n * There is no create path to exempt, and that is deliberate rather than\n * an oversight: unlike a new row at a fresh uid, this writes a FIXED\n * document path, so the all-defaults `current` produced when the cache\n * has never seen this doc is not the harmless blank a fresh uid would\n * be. It would put `USD`, guest checkout on and two null template ids\n * over whatever the server really holds.\n *\n * The guard WRAPS the write — an early return is a shape you can keep\n * while losing the protection.\n */\n const verdict = await writeGuardedBySeed(\n {\n subject: 'store settings',\n unreadable: storeStatus === 'error',\n fromCache: storeFromCache,\n },\n async () => {\n // The product and collection templates, the currency and the\n // checkout rules render on the live store with no publish step, so\n // the save carries the site's cache drop with it.\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.set(\n doc(firestore, 'hosts', hostId, 'settings', 'store'),\n {\n pdpScreenId: current.pdpScreenId || null,\n collectionScreenId: current.collectionScreenId || null,\n currency: current.currency ?? 'USD',\n guestCheckout: current.guestCheckout !== false,\n termsUrl: current.termsUrl || null,\n receiptFooter: current.receiptFooter || null,\n },\n { merge: true },\n ),\n })\n },\n )\n // Before `setDraft(null)`, so a refusal keeps every typed value on\n // screen. A save that silently does nothing sends the user back to\n // retype a form that will be refused again just as quietly.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n setDraft(null)\n enqueueSnackbar('Store settings saved', {\n variant: 'success',\n persist: false,\n })\n }, [\n current,\n firestore,\n hostId,\n user,\n enqueueSnackbar,\n storeStatus,\n storeFromCache,\n ])\n\n return (\n <CardDisplay\n header={'Store settings'}\n help={pluginDocsHelp('commerce', { anchor: '#store-settings' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1.5}>\n <TextField\n label=\"Product page template\"\n value={current.pdpScreenId ?? ''}\n onChange={(event) => update({ pdpScreenId: event.target.value })}\n size=\"small\"\n select\n helperText={\n 'Page rendered at /products/{slug} — design it in the ' +\n 'Besigner with the Product detail block and {{product.*}} tokens.'\n }\n >\n <MenuItem value=\"\">{'None (product URLs 404)'}</MenuItem>\n {screenEntries.map(([screenId, path]) => (\n <MenuItem key={screenId} value={screenId}>\n {`/${path === '/' ? '' : path}`}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n label=\"Collection page template\"\n value={current.collectionScreenId ?? ''}\n onChange={(event) =>\n update({ collectionScreenId: event.target.value })\n }\n size=\"small\"\n select\n helperText={\n 'Page rendered at /collections/{slug} — drop a Product grid ' +\n 'with source \"A collection\" and {{collection.*}} tokens.'\n }\n >\n <MenuItem value=\"\">{'None (collection URLs 404)'}</MenuItem>\n {screenEntries.map(([screenId, path]) => (\n <MenuItem key={screenId} value={screenId}>\n {`/${path === '/' ? '' : path}`}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n label=\"Currency\"\n value={current.currency ?? 'USD'}\n onChange={(event) => update({ currency: event.target.value })}\n size=\"small\"\n select\n sx={{ maxWidth: 200 }}\n helperText=\"Charges settle in USD; more currencies are coming\"\n >\n <MenuItem value=\"USD\">{'USD ($)'}</MenuItem>\n </TextField>\n <FormControlLabel\n control={\n <Switch\n size=\"small\"\n checked={current.guestCheckout !== false}\n onChange={(event) =>\n update({ guestCheckout: event.target.checked })\n }\n />\n }\n label=\"Allow guest checkout (no account required)\"\n />\n <TextField\n label=\"Terms URL\"\n value={current.termsUrl ?? ''}\n onChange={(event) => update({ termsUrl: event.target.value })}\n size=\"small\"\n placeholder=\"/terms\"\n helperText=\"Linked from checkout when set\"\n />\n <TextField\n label=\"Receipt footer\"\n value={current.receiptFooter ?? ''}\n onChange={(event) => update({ receiptFooter: event.target.value })}\n size=\"small\"\n multiline\n minRows={2}\n placeholder=\"Thanks for supporting our shop!\"\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Password protection and maintenance mode live under Site ' +\n 'Protection.'}\n </Typography>\n <Button\n variant=\"contained\"\n color=\"primary\"\n size=\"small\"\n disabled={!draft}\n onClick={handleSave}\n sx={{ alignSelf: 'flex-start' }}\n >\n {'Save store settings'}\n </Button>\n </Stack>\n </CardDisplay>\n )\n}\nStoreSettingsCard.displayName = 'StoreSettingsCard'\n\nexport default StoreSettingsCard\n"],"names":["CardDisplay","useSnackbar","Button","FormControlLabel","MenuItem","Stack","Switch","TextField","Typography","doc","useCallback","useState","useFirestore","useUser","useFirestoreDoc","writeGuardedBySeed","pluginDocsHelp","writeSiteWideChange","StoreSettingsCard","props","current","hostId","firestore","data","user","enqueueSnackbar","store","status","storeStatus","fromCache","storeFromCache","host","draft","setDraft","pdpScreenId","collectionScreenId","currency","guestCheckout","termsUrl","receiptFooter","update","patch","screenEntries","Object","entries","screens","sort","a","b","String","localeCompare","handleSave","verdict","subject","unreadable","write","batch","set","merge","ok","message","variant","persist","header","help","anchor","contentGutterX","contentGutterY","spacing","label","value","onChange","event","target","size","select","helperText","map","screenId","path","sx","maxWidth","control","checked","placeholder","multiline","minRows","color","disabled","onClick","alignSelf","displayName"],"mappings":"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"}
@@ -146,9 +146,12 @@ import { pluginDocsHelp } from "@aglyn/aglyn";
146
146
  storeFromCache
147
147
  ]);
148
148
  return /*#__PURE__*/ _jsx(CardDisplay, {
149
+ // Another plugin's card scrolls here (the tax service's "Go to Taxes",
150
+ // AGL-3693), restating this id rather than importing this package.
151
+ id: "commerce-store-taxes",
149
152
  header: 'Taxes',
150
153
  help: pluginDocsHelp('commerce', {
151
- anchor: '#shipping--taxes'
154
+ anchor: '#tax-settings'
152
155
  }),
153
156
  contentGutterX: true,
154
157
  contentGutterY: true,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/tax-settings-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport * as CommerceModel from '../../model'\nimport { PLATFORM_BRAND_NAME } from '@aglyn/aglyn/app-utils/platform-brand'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n Alert,\n Button,\n Divider,\n FormControlLabel,\n MenuItem,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport { doc, setDoc } from 'firebase/firestore'\nimport { useCallback, useState } from 'react'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport {\n useFirestoreDoc,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\n\nexport interface TaxSettingsCardProps {\n hostId: string\n}\n\n/**\n * Tax settings (AGL-285): manual per-region rates (most-specific wins)\n * or Stripe Tax automatic calculation, stored on\n * `hosts/{hostId}/settings/store` under `tax`. The legacy quick-buy\n * checkout taxes by the store origin; Checkout v2 taxes by destination.\n */\nexport function TaxSettingsCard(props: TaxSettingsCardProps) {\n const { hostId } = props\n const firestore = useFirestore()\n const { enqueueSnackbar } = useSnackbar()\n const {\n data: store,\n status: storeStatus,\n /**\n * The settings doc this form is seeded from is unconfirmed by the server\n * (AGL-1358). `current` is `draft ?? store?.tax ?? {mode: 'manual'}` and\n * the save writes `{tax: current}`, so `merge: true` protects the doc's\n * other maps and nothing inside this one. `mode` is the field that costs\n * money: a cached seed flipping `stripe` back to `manual` stops automatic\n * tax calculation — `resolveTaxRate` returns null in stripe mode — and\n * the store under-collects with nothing anywhere reporting it.\n */\n fromCache: storeFromCache,\n } = useFirestoreDoc<any>(\n () => doc(firestore, 'hosts', hostId, 'settings', 'store'),\n [firestore, hostId],\n )\n const [draft, setDraft] = useState<CommerceModel.TaxSettings | null>(null)\n const current: CommerceModel.TaxSettings = draft ?? store?.tax ?? { mode: 'manual' }\n /**\n * Whether anyone has ever answered the tax question for this store\n * (AGL-1999). Read from the SAVED document, never from `current` — the\n * `{ mode: 'manual' }` seed above is local state that has never reached\n * Firestore, and it is exactly what made this invisible: the card looked\n * configured while the server saw `mode: undefined`, took no branch, and\n * sold untaxed. Every storefront path now refuses that state, so the card\n * has to show it rather than paper over it.\n */\n const decided =\n storeStatus !== 'loading' && typeof store?.tax?.mode === 'string'\n const update = (patch: Partial<CommerceModel.TaxSettings>) =>\n setDraft({ ...current, ...patch })\n const updateRate = (\n index: number,\n patch: Partial<CommerceModel.TaxRate> | null,\n ) => {\n const rates = [...(current.rates ?? [])]\n if (patch === null) rates.splice(index, 1)\n else rates[index] = { country: '', pct: 0, ...rates[index], ...patch }\n update({ rates })\n }\n /**\n * One of the flat, per-regime rates (AGL-1969 lodging, AGL-2028 services).\n *\n * A blank field clears the rate rather than storing `NaN`: clearing is how a\n * merchant turns the regime back off, and `Number('')` is 0 while\n * `Number(' ')` is also 0 — neither of which should ever reach the document\n * as a \"rate\".\n */\n const updateFlat = (\n key: 'lodging' | 'service',\n patch: Partial<CommerceModel.FlatTaxRate>,\n ) => update({ [key]: { ...current[key], ...patch } })\n const flatPctText = (key: 'lodging' | 'service') => {\n const pct = current[key]?.pct\n return pct === undefined || pct === null ? '' : String(pct)\n }\n /**\n * Shown under a typed rate this will NOT apply. Silence here would be the\n * failure: `resolveFlatTaxCents` treats an out-of-range percentage as off,\n * so a decimal-point typo would otherwise save cleanly and collect nothing.\n */\n const flatPctProblem = (key: 'lodging' | 'service'): string | null => {\n const raw = current[key]?.pct\n if (raw === undefined || raw === null || String(raw) === '') return null\n if (Number(raw) === 0) return null\n return CommerceModel.isUsableFlatTaxPct(raw)\n ? null\n : `Enter a percentage between 0 and ${CommerceModel.FLAT_TAX_MAX_PCT}. ` +\n 'This rate is not being applied.'\n }\n\n const handleSave = useCallback(async () => {\n /**\n * Refuse a save whose seed the server never confirmed (AGL-1358).\n *\n * No create path to exempt: this is a FIXED document path, so the\n * `{mode: 'manual'}` default produced when the cache has never seen the\n * map is not the harmless blank a fresh uid would be — writing it turns\n * automatic tax calculation off on a store that had it on.\n *\n * The guard WRAPS the write — an early return is a shape you can keep\n * while losing the protection.\n */\n const verdict = await writeGuardedBySeed(\n {\n subject: 'tax settings',\n unreadable: storeStatus === 'error',\n fromCache: storeFromCache,\n },\n async () => {\n await setDoc(\n doc(firestore, 'hosts', hostId, 'settings', 'store'),\n { tax: current },\n { merge: true },\n )\n },\n )\n // Before `setDraft(null)`, so a refusal keeps every typed rate on screen.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n setDraft(null)\n enqueueSnackbar('Tax settings saved', { variant: 'success', persist: false })\n }, [current, firestore, hostId, enqueueSnackbar, storeStatus, storeFromCache])\n\n return (\n <CardDisplay\n header={'Taxes'}\n help={pluginDocsHelp('commerce', { anchor: '#shipping--taxes' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1.5}>\n {decided ? null : (\n // The store is not selling. Saying so here is the whole point: the\n // silent version of this state charged shoppers an untaxed total.\n <Alert severity=\"warning\">\n {'Choose how this store handles sales tax and save. Until you ' +\n 'do, checkout is turned off — we won’t take an order we can’t ' +\n 'tax correctly.'}\n </Alert>\n )}\n <TextField\n label=\"Calculation\"\n value={current.mode ?? 'manual'}\n onChange={(event) =>\n update({\n mode: event.target.value as 'manual' | 'stripe' | 'none',\n })\n }\n size=\"small\"\n select\n sx={{ maxWidth: 280 }}\n >\n <MenuItem value=\"manual\">{'Manual rates (below)'}</MenuItem>\n <MenuItem value=\"stripe\">{'Stripe Tax (automatic)'}</MenuItem>\n {/* An explicit decision, not an omission (AGL-1999) — the option a\n merchant under a nexus threshold, or selling non-taxable goods,\n needs in order to sell at all. */}\n <MenuItem value=\"none\">{'Don’t collect sales tax'}</MenuItem>\n </TextField>\n {current.mode === 'none' ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'This store adds no sales tax to any order. Orders still go ' +\n 'through — the decision is recorded, not the tax.'}\n </Typography>\n ) : current.mode === 'stripe' ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Stripe Tax calculates per buyer location at checkout. ' +\n 'Activate Stripe Tax in your Stripe dashboard first.'}\n </Typography>\n ) : (\n <>\n <FormControlLabel\n control={\n <Switch\n size=\"small\"\n checked={Boolean(current.pricesIncludeTax)}\n onChange={(event) =>\n update({ pricesIncludeTax: event.target.checked })\n }\n />\n }\n label=\"Prices include tax (VAT-style)\"\n />\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Origin country\"\n value={current.origin?.country ?? ''}\n onChange={(event) =>\n update({\n origin: {\n ...current.origin,\n country: event.target.value.toUpperCase().slice(0, 2),\n },\n })\n }\n size=\"small\"\n sx={{ width: 140 }}\n placeholder=\"US\"\n />\n <TextField\n label=\"Origin state\"\n value={current.origin?.state ?? ''}\n onChange={(event) =>\n update({\n origin: {\n ...current.origin,\n state: event.target.value.toUpperCase().slice(0, 3),\n },\n })\n }\n size=\"small\"\n sx={{ width: 140 }}\n placeholder=\"TX\"\n />\n </Stack>\n {/* Which of the product's three addresses this is. A merchant\n who reads an unlabeled origin as \"our address\" may set it\n from the wrong one: the address the workspace pays Aglyn\n from is a different jurisdiction question, and the payout\n identity is a third. Naming the two it is NOT costs a line\n and prevents a mis-taxed order. */}\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Where this store ships or sells FROM — the jurisdiction the ' +\n 'manual rates below are applied from. Not the address your ' +\n 'workspace is billed at by Aglyn, and not where your payouts ' +\n 'are sent.'}\n </Typography>\n {(current.rates ?? []).map((rate, index) => (\n <Stack key={index} direction=\"row\" spacing={1}>\n <TextField\n label=\"Country\"\n value={rate.country}\n onChange={(event) =>\n updateRate(index, {\n country: event.target.value.toUpperCase().slice(0, 2),\n })\n }\n size=\"small\"\n sx={{ width: 90 }}\n />\n <TextField\n label=\"State\"\n value={rate.state ?? ''}\n onChange={(event) =>\n updateRate(index, {\n state:\n event.target.value.toUpperCase().slice(0, 3) ||\n undefined,\n })\n }\n size=\"small\"\n sx={{ width: 80 }}\n />\n <TextField\n label=\"%\"\n value={rate.pct}\n onChange={(event) =>\n updateRate(index, { pct: Number(event.target.value) || 0 })\n }\n size=\"small\"\n sx={{ width: 80 }}\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n <TextField\n label=\"Label\"\n value={rate.label ?? ''}\n onChange={(event) =>\n updateRate(index, { label: event.target.value })\n }\n size=\"small\"\n sx={{ flex: 1 }}\n placeholder=\"Sales tax\"\n />\n <Button\n size=\"small\"\n color=\"error\"\n onClick={() => updateRate(index, null)}\n >\n {'✕'}\n </Button>\n </Stack>\n ))}\n <Button\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={() => updateRate(current.rates?.length ?? 0, {})}\n >\n {'Add rate'}\n </Button>\n </>\n )}\n {/*\n LODGING TAX (AGL-1969) — deliberately OUTSIDE the calculation branch\n above, and deliberately not a `rates[]` row.\n\n The setting above is a goods SALES rate resolved against an address.\n Occupancy tax is a different regime with its own rates, registration\n and return, and it applies to reservations, which sell nights rather\n than goods. Nesting it under \"Manual rates\" would have said the two\n are the same machinery; putting it here says a store on Stripe Tax —\n which cannot compute occupancy tax from these sessions at all — can\n still set one.\n\n It is off until the merchant fills it in, so nothing an existing\n store charges moves.\n */}\n <Divider sx={{ my: 0.5 }} />\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Lodging tax'}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Charged on reservations, on top of the price, using the rate ' +\n 'you enter here. It is separate from the sales tax above ' +\n 'because occupancy tax is its own regime with its own rates ' +\n 'and its own return. Leave it blank to charge none — that is ' +\n 'the default.'}\n </Typography>\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Rate %\"\n value={flatPctText('lodging')}\n onChange={(event) =>\n updateFlat('lodging', {\n pct:\n event.target.value === ''\n ? undefined\n : Number(event.target.value),\n })\n }\n size=\"small\"\n sx={{ width: 110 }}\n placeholder=\"0\"\n error={Boolean(flatPctProblem('lodging'))}\n helperText={flatPctProblem('lodging') ?? ' '}\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n <TextField\n label=\"Label\"\n value={current.lodging?.label ?? ''}\n onChange={(event) =>\n updateFlat('lodging', { label: event.target.value })\n }\n size=\"small\"\n sx={{ flex: 1 }}\n placeholder=\"Occupancy tax\"\n helperText=\"Shown to the guest on the receipt\"\n />\n </Stack>\n {/*\n MECHANISM ONLY, AND NO REMITTANCE DETERMINATION.\n\n Whether a jurisdiction imposes occupancy tax, who must register for\n it and who must remit it are legal conclusions that attach by\n operation of law (AGL-1904/AGL-1956) and are the merchant's under\n the Terms. This copy says what the software DOES and what it does\n not do, and stops there — including the deposit basis, which is a\n real limitation rather than an answer this product has taken.\n */}\n <Alert severity=\"info\">\n {`${PLATFORM_BRAND_NAME} applies the rate you enter and records ` +\n 'what was charged. It does not determine whether this tax ' +\n 'applies to you, at what rate, or where it should be paid — ' +\n 'that is yours to decide.'}\n </Alert>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'On a reservation that takes a deposit, the rate is applied to ' +\n 'the deposit — the amount actually charged here — not to the ' +\n 'whole stay. If tax is due on the full stay, collect the ' +\n 'difference the same way you collect the rest of the balance.'}\n </Typography>\n </Stack>\n {/*\n SERVICE TAX (AGL-2028) — the bookings sibling of the block above,\n and here for the same reason it is not in the bookings plugin's own\n settings: this is the one card a merchant comes to with a tax\n question, and a second tax surface elsewhere is how one of them ends\n up unanswered.\n\n Its EXISTENCE is also the opt-in AGL-2000 wanted. That issue\n declined to apply the goods rate to an appointment partly because\n nothing said the merchant meant these settings to cover bookings; a\n field labelled for services, blank until they fill it in, is them\n saying so.\n */}\n <Divider sx={{ my: 0.5 }} />\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Service tax'}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Charged on paid bookings, on top of the price, using the rate ' +\n 'you enter here. It is separate from the sales tax above ' +\n 'because whether a service is taxable is often a different ' +\n 'question from whether goods are. Leave it blank to charge ' +\n 'none — that is the default.'}\n </Typography>\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Rate %\"\n value={flatPctText('service')}\n onChange={(event) =>\n updateFlat('service', {\n pct:\n event.target.value === ''\n ? undefined\n : Number(event.target.value),\n })\n }\n size=\"small\"\n sx={{ width: 110 }}\n placeholder=\"0\"\n error={Boolean(flatPctProblem('service'))}\n helperText={flatPctProblem('service') ?? ' '}\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n <TextField\n label=\"Label\"\n value={current.service?.label ?? ''}\n onChange={(event) =>\n updateFlat('service', { label: event.target.value })\n }\n size=\"small\"\n sx={{ flex: 1 }}\n placeholder=\"Service tax\"\n helperText=\"Shown to the client on the receipt\"\n />\n </Stack>\n {/* MECHANISM ONLY, AND NO REMITTANCE DETERMINATION — see the\n lodging block above. */}\n <Alert severity=\"info\">\n {`${PLATFORM_BRAND_NAME} applies the rate you enter and records ` +\n 'what was charged. It does not determine whether this tax ' +\n 'applies to you, at what rate, or where it should be paid — ' +\n 'that is yours to decide.'}\n </Alert>\n </Stack>\n <Button\n variant=\"contained\"\n color=\"primary\"\n size=\"small\"\n disabled={!draft}\n onClick={handleSave}\n sx={{ alignSelf: 'flex-start' }}\n >\n {'Save tax settings'}\n </Button>\n </Stack>\n </CardDisplay>\n )\n}\nTaxSettingsCard.displayName = 'TaxSettingsCard'\n\nexport default TaxSettingsCard\n"],"names":["CommerceModel","PLATFORM_BRAND_NAME","CardDisplay","useSnackbar","Alert","Button","Divider","FormControlLabel","MenuItem","Stack","Switch","TextField","Typography","doc","setDoc","useCallback","useState","useFirestore","useFirestoreDoc","writeGuardedBySeed","pluginDocsHelp","TaxSettingsCard","props","draft","current","flatPctProblem","store","hostId","firestore","enqueueSnackbar","data","status","storeStatus","fromCache","storeFromCache","setDraft","tax","mode","decided","update","patch","updateRate","index","rates","splice","country","pct","updateFlat","key","flatPctText","undefined","String","raw","Number","isUsableFlatTaxPct","FLAT_TAX_MAX_PCT","handleSave","verdict","subject","unreadable","merge","ok","message","variant","persist","header","help","anchor","contentGutterX","contentGutterY","spacing","severity","label","value","onChange","event","target","size","select","sx","maxWidth","color","control","checked","Boolean","pricesIncludeTax","direction","origin","toUpperCase","slice","width","placeholder","state","map","rate","slotProps","htmlInput","inputMode","flex","onClick","alignSelf","length","my","error","helperText","lodging","service","disabled","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/tax-settings-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport * as CommerceModel from '../../model'\nimport { PLATFORM_BRAND_NAME } from '@aglyn/aglyn/app-utils/platform-brand'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n Alert,\n Button,\n Divider,\n FormControlLabel,\n MenuItem,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport { doc, setDoc } from 'firebase/firestore'\nimport { useCallback, useState } from 'react'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport {\n useFirestoreDoc,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\n\nexport interface TaxSettingsCardProps {\n hostId: string\n}\n\n/**\n * Tax settings (AGL-285): manual per-region rates (most-specific wins)\n * or Stripe Tax automatic calculation, stored on\n * `hosts/{hostId}/settings/store` under `tax`. The legacy quick-buy\n * checkout taxes by the store origin; Checkout v2 taxes by destination.\n */\nexport function TaxSettingsCard(props: TaxSettingsCardProps) {\n const { hostId } = props\n const firestore = useFirestore()\n const { enqueueSnackbar } = useSnackbar()\n const {\n data: store,\n status: storeStatus,\n /**\n * The settings doc this form is seeded from is unconfirmed by the server\n * (AGL-1358). `current` is `draft ?? store?.tax ?? {mode: 'manual'}` and\n * the save writes `{tax: current}`, so `merge: true` protects the doc's\n * other maps and nothing inside this one. `mode` is the field that costs\n * money: a cached seed flipping `stripe` back to `manual` stops automatic\n * tax calculation — `resolveTaxRate` returns null in stripe mode — and\n * the store under-collects with nothing anywhere reporting it.\n */\n fromCache: storeFromCache,\n } = useFirestoreDoc<any>(\n () => doc(firestore, 'hosts', hostId, 'settings', 'store'),\n [firestore, hostId],\n )\n const [draft, setDraft] = useState<CommerceModel.TaxSettings | null>(null)\n const current: CommerceModel.TaxSettings = draft ?? store?.tax ?? { mode: 'manual' }\n /**\n * Whether anyone has ever answered the tax question for this store\n * (AGL-1999). Read from the SAVED document, never from `current` — the\n * `{ mode: 'manual' }` seed above is local state that has never reached\n * Firestore, and it is exactly what made this invisible: the card looked\n * configured while the server saw `mode: undefined`, took no branch, and\n * sold untaxed. Every storefront path now refuses that state, so the card\n * has to show it rather than paper over it.\n */\n const decided =\n storeStatus !== 'loading' && typeof store?.tax?.mode === 'string'\n const update = (patch: Partial<CommerceModel.TaxSettings>) =>\n setDraft({ ...current, ...patch })\n const updateRate = (\n index: number,\n patch: Partial<CommerceModel.TaxRate> | null,\n ) => {\n const rates = [...(current.rates ?? [])]\n if (patch === null) rates.splice(index, 1)\n else rates[index] = { country: '', pct: 0, ...rates[index], ...patch }\n update({ rates })\n }\n /**\n * One of the flat, per-regime rates (AGL-1969 lodging, AGL-2028 services).\n *\n * A blank field clears the rate rather than storing `NaN`: clearing is how a\n * merchant turns the regime back off, and `Number('')` is 0 while\n * `Number(' ')` is also 0 — neither of which should ever reach the document\n * as a \"rate\".\n */\n const updateFlat = (\n key: 'lodging' | 'service',\n patch: Partial<CommerceModel.FlatTaxRate>,\n ) => update({ [key]: { ...current[key], ...patch } })\n const flatPctText = (key: 'lodging' | 'service') => {\n const pct = current[key]?.pct\n return pct === undefined || pct === null ? '' : String(pct)\n }\n /**\n * Shown under a typed rate this will NOT apply. Silence here would be the\n * failure: `resolveFlatTaxCents` treats an out-of-range percentage as off,\n * so a decimal-point typo would otherwise save cleanly and collect nothing.\n */\n const flatPctProblem = (key: 'lodging' | 'service'): string | null => {\n const raw = current[key]?.pct\n if (raw === undefined || raw === null || String(raw) === '') return null\n if (Number(raw) === 0) return null\n return CommerceModel.isUsableFlatTaxPct(raw)\n ? null\n : `Enter a percentage between 0 and ${CommerceModel.FLAT_TAX_MAX_PCT}. ` +\n 'This rate is not being applied.'\n }\n\n const handleSave = useCallback(async () => {\n /**\n * Refuse a save whose seed the server never confirmed (AGL-1358).\n *\n * No create path to exempt: this is a FIXED document path, so the\n * `{mode: 'manual'}` default produced when the cache has never seen the\n * map is not the harmless blank a fresh uid would be — writing it turns\n * automatic tax calculation off on a store that had it on.\n *\n * The guard WRAPS the write — an early return is a shape you can keep\n * while losing the protection.\n */\n const verdict = await writeGuardedBySeed(\n {\n subject: 'tax settings',\n unreadable: storeStatus === 'error',\n fromCache: storeFromCache,\n },\n async () => {\n await setDoc(\n doc(firestore, 'hosts', hostId, 'settings', 'store'),\n { tax: current },\n { merge: true },\n )\n },\n )\n // Before `setDraft(null)`, so a refusal keeps every typed rate on screen.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n setDraft(null)\n enqueueSnackbar('Tax settings saved', { variant: 'success', persist: false })\n }, [current, firestore, hostId, enqueueSnackbar, storeStatus, storeFromCache])\n\n return (\n <CardDisplay\n // Another plugin's card scrolls here (the tax service's \"Go to Taxes\",\n // AGL-3693), restating this id rather than importing this package.\n id=\"commerce-store-taxes\"\n header={'Taxes'}\n help={pluginDocsHelp('commerce', { anchor: '#tax-settings' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1.5}>\n {decided ? null : (\n // The store is not selling. Saying so here is the whole point: the\n // silent version of this state charged shoppers an untaxed total.\n <Alert severity=\"warning\">\n {'Choose how this store handles sales tax and save. Until you ' +\n 'do, checkout is turned off — we won’t take an order we can’t ' +\n 'tax correctly.'}\n </Alert>\n )}\n <TextField\n label=\"Calculation\"\n value={current.mode ?? 'manual'}\n onChange={(event) =>\n update({\n mode: event.target.value as 'manual' | 'stripe' | 'none',\n })\n }\n size=\"small\"\n select\n sx={{ maxWidth: 280 }}\n >\n <MenuItem value=\"manual\">{'Manual rates (below)'}</MenuItem>\n <MenuItem value=\"stripe\">{'Stripe Tax (automatic)'}</MenuItem>\n {/* An explicit decision, not an omission (AGL-1999) — the option a\n merchant under a nexus threshold, or selling non-taxable goods,\n needs in order to sell at all. */}\n <MenuItem value=\"none\">{'Don’t collect sales tax'}</MenuItem>\n </TextField>\n {current.mode === 'none' ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'This store adds no sales tax to any order. Orders still go ' +\n 'through — the decision is recorded, not the tax.'}\n </Typography>\n ) : current.mode === 'stripe' ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Stripe Tax calculates per buyer location at checkout. ' +\n 'Activate Stripe Tax in your Stripe dashboard first.'}\n </Typography>\n ) : (\n <>\n <FormControlLabel\n control={\n <Switch\n size=\"small\"\n checked={Boolean(current.pricesIncludeTax)}\n onChange={(event) =>\n update({ pricesIncludeTax: event.target.checked })\n }\n />\n }\n label=\"Prices include tax (VAT-style)\"\n />\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Origin country\"\n value={current.origin?.country ?? ''}\n onChange={(event) =>\n update({\n origin: {\n ...current.origin,\n country: event.target.value.toUpperCase().slice(0, 2),\n },\n })\n }\n size=\"small\"\n sx={{ width: 140 }}\n placeholder=\"US\"\n />\n <TextField\n label=\"Origin state\"\n value={current.origin?.state ?? ''}\n onChange={(event) =>\n update({\n origin: {\n ...current.origin,\n state: event.target.value.toUpperCase().slice(0, 3),\n },\n })\n }\n size=\"small\"\n sx={{ width: 140 }}\n placeholder=\"TX\"\n />\n </Stack>\n {/* Which of the product's three addresses this is. A merchant\n who reads an unlabeled origin as \"our address\" may set it\n from the wrong one: the address the workspace pays Aglyn\n from is a different jurisdiction question, and the payout\n identity is a third. Naming the two it is NOT costs a line\n and prevents a mis-taxed order. */}\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Where this store ships or sells FROM — the jurisdiction the ' +\n 'manual rates below are applied from. Not the address your ' +\n 'workspace is billed at by Aglyn, and not where your payouts ' +\n 'are sent.'}\n </Typography>\n {(current.rates ?? []).map((rate, index) => (\n <Stack key={index} direction=\"row\" spacing={1}>\n <TextField\n label=\"Country\"\n value={rate.country}\n onChange={(event) =>\n updateRate(index, {\n country: event.target.value.toUpperCase().slice(0, 2),\n })\n }\n size=\"small\"\n sx={{ width: 90 }}\n />\n <TextField\n label=\"State\"\n value={rate.state ?? ''}\n onChange={(event) =>\n updateRate(index, {\n state:\n event.target.value.toUpperCase().slice(0, 3) ||\n undefined,\n })\n }\n size=\"small\"\n sx={{ width: 80 }}\n />\n <TextField\n label=\"%\"\n value={rate.pct}\n onChange={(event) =>\n updateRate(index, { pct: Number(event.target.value) || 0 })\n }\n size=\"small\"\n sx={{ width: 80 }}\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n <TextField\n label=\"Label\"\n value={rate.label ?? ''}\n onChange={(event) =>\n updateRate(index, { label: event.target.value })\n }\n size=\"small\"\n sx={{ flex: 1 }}\n placeholder=\"Sales tax\"\n />\n <Button\n size=\"small\"\n color=\"error\"\n onClick={() => updateRate(index, null)}\n >\n {'✕'}\n </Button>\n </Stack>\n ))}\n <Button\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={() => updateRate(current.rates?.length ?? 0, {})}\n >\n {'Add rate'}\n </Button>\n </>\n )}\n {/*\n LODGING TAX (AGL-1969) — deliberately OUTSIDE the calculation branch\n above, and deliberately not a `rates[]` row.\n\n The setting above is a goods SALES rate resolved against an address.\n Occupancy tax is a different regime with its own rates, registration\n and return, and it applies to reservations, which sell nights rather\n than goods. Nesting it under \"Manual rates\" would have said the two\n are the same machinery; putting it here says a store on Stripe Tax —\n which cannot compute occupancy tax from these sessions at all — can\n still set one.\n\n It is off until the merchant fills it in, so nothing an existing\n store charges moves.\n */}\n <Divider sx={{ my: 0.5 }} />\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Lodging tax'}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Charged on reservations, on top of the price, using the rate ' +\n 'you enter here. It is separate from the sales tax above ' +\n 'because occupancy tax is its own regime with its own rates ' +\n 'and its own return. Leave it blank to charge none — that is ' +\n 'the default.'}\n </Typography>\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Rate %\"\n value={flatPctText('lodging')}\n onChange={(event) =>\n updateFlat('lodging', {\n pct:\n event.target.value === ''\n ? undefined\n : Number(event.target.value),\n })\n }\n size=\"small\"\n sx={{ width: 110 }}\n placeholder=\"0\"\n error={Boolean(flatPctProblem('lodging'))}\n helperText={flatPctProblem('lodging') ?? ' '}\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n <TextField\n label=\"Label\"\n value={current.lodging?.label ?? ''}\n onChange={(event) =>\n updateFlat('lodging', { label: event.target.value })\n }\n size=\"small\"\n sx={{ flex: 1 }}\n placeholder=\"Occupancy tax\"\n helperText=\"Shown to the guest on the receipt\"\n />\n </Stack>\n {/*\n MECHANISM ONLY, AND NO REMITTANCE DETERMINATION.\n\n Whether a jurisdiction imposes occupancy tax, who must register for\n it and who must remit it are legal conclusions that attach by\n operation of law (AGL-1904/AGL-1956) and are the merchant's under\n the Terms. This copy says what the software DOES and what it does\n not do, and stops there — including the deposit basis, which is a\n real limitation rather than an answer this product has taken.\n */}\n <Alert severity=\"info\">\n {`${PLATFORM_BRAND_NAME} applies the rate you enter and records ` +\n 'what was charged. It does not determine whether this tax ' +\n 'applies to you, at what rate, or where it should be paid — ' +\n 'that is yours to decide.'}\n </Alert>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'On a reservation that takes a deposit, the rate is applied to ' +\n 'the deposit — the amount actually charged here — not to the ' +\n 'whole stay. If tax is due on the full stay, collect the ' +\n 'difference the same way you collect the rest of the balance.'}\n </Typography>\n </Stack>\n {/*\n SERVICE TAX (AGL-2028) — the bookings sibling of the block above,\n and here for the same reason it is not in the bookings plugin's own\n settings: this is the one card a merchant comes to with a tax\n question, and a second tax surface elsewhere is how one of them ends\n up unanswered.\n\n Its EXISTENCE is also the opt-in AGL-2000 wanted. That issue\n declined to apply the goods rate to an appointment partly because\n nothing said the merchant meant these settings to cover bookings; a\n field labelled for services, blank until they fill it in, is them\n saying so.\n */}\n <Divider sx={{ my: 0.5 }} />\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Service tax'}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Charged on paid bookings, on top of the price, using the rate ' +\n 'you enter here. It is separate from the sales tax above ' +\n 'because whether a service is taxable is often a different ' +\n 'question from whether goods are. Leave it blank to charge ' +\n 'none — that is the default.'}\n </Typography>\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Rate %\"\n value={flatPctText('service')}\n onChange={(event) =>\n updateFlat('service', {\n pct:\n event.target.value === ''\n ? undefined\n : Number(event.target.value),\n })\n }\n size=\"small\"\n sx={{ width: 110 }}\n placeholder=\"0\"\n error={Boolean(flatPctProblem('service'))}\n helperText={flatPctProblem('service') ?? ' '}\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n <TextField\n label=\"Label\"\n value={current.service?.label ?? ''}\n onChange={(event) =>\n updateFlat('service', { label: event.target.value })\n }\n size=\"small\"\n sx={{ flex: 1 }}\n placeholder=\"Service tax\"\n helperText=\"Shown to the client on the receipt\"\n />\n </Stack>\n {/* MECHANISM ONLY, AND NO REMITTANCE DETERMINATION — see the\n lodging block above. */}\n <Alert severity=\"info\">\n {`${PLATFORM_BRAND_NAME} applies the rate you enter and records ` +\n 'what was charged. It does not determine whether this tax ' +\n 'applies to you, at what rate, or where it should be paid — ' +\n 'that is yours to decide.'}\n </Alert>\n </Stack>\n <Button\n variant=\"contained\"\n color=\"primary\"\n size=\"small\"\n disabled={!draft}\n onClick={handleSave}\n sx={{ alignSelf: 'flex-start' }}\n >\n {'Save tax settings'}\n </Button>\n </Stack>\n </CardDisplay>\n )\n}\nTaxSettingsCard.displayName = 'TaxSettingsCard'\n\nexport default TaxSettingsCard\n"],"names":["CommerceModel","PLATFORM_BRAND_NAME","CardDisplay","useSnackbar","Alert","Button","Divider","FormControlLabel","MenuItem","Stack","Switch","TextField","Typography","doc","setDoc","useCallback","useState","useFirestore","useFirestoreDoc","writeGuardedBySeed","pluginDocsHelp","TaxSettingsCard","props","draft","current","flatPctProblem","store","hostId","firestore","enqueueSnackbar","data","status","storeStatus","fromCache","storeFromCache","setDraft","tax","mode","decided","update","patch","updateRate","index","rates","splice","country","pct","updateFlat","key","flatPctText","undefined","String","raw","Number","isUsableFlatTaxPct","FLAT_TAX_MAX_PCT","handleSave","verdict","subject","unreadable","merge","ok","message","variant","persist","id","header","help","anchor","contentGutterX","contentGutterY","spacing","severity","label","value","onChange","event","target","size","select","sx","maxWidth","color","control","checked","Boolean","pricesIncludeTax","direction","origin","toUpperCase","slice","width","placeholder","state","map","rate","slotProps","htmlInput","inputMode","flex","onClick","alignSelf","length","my","error","helperText","lodging","service","disabled","displayName"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { _ as _extends } from "@swc/helpers/_/_extends";
2
2
  import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
3
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
4
4
  /**
5
5
  * @license
6
6
  * Copyright 2026 Aglyn LLC
@@ -302,6 +302,29 @@ function dateLabel(atMs) {
302
302
  variant: "body2",
303
303
  color: "text.secondary",
304
304
  children: view.localDelivery.windowLabel
305
+ }) : null,
306
+ view.localDelivery.courier ? /*#__PURE__*/ _jsxs(_Fragment, {
307
+ children: [
308
+ /*#__PURE__*/ _jsx(Typography, {
309
+ variant: "body2",
310
+ children: `${view.localDelivery.courier.providerLabel}: ${view.localDelivery.courier.stateLabel}`
311
+ }),
312
+ view.localDelivery.courier.etaMs ? /*#__PURE__*/ _jsx(Typography, {
313
+ variant: "body2",
314
+ color: "text.secondary",
315
+ children: `Arriving about ${new Date(view.localDelivery.courier.etaMs).toLocaleTimeString([], {
316
+ hour: 'numeric',
317
+ minute: '2-digit'
318
+ })}`
319
+ }) : null,
320
+ view.localDelivery.courier.trackingUrl ? /*#__PURE__*/ _jsx(Link, {
321
+ href: view.localDelivery.courier.trackingUrl,
322
+ target: "_blank",
323
+ rel: "noopener noreferrer",
324
+ variant: "body2",
325
+ children: 'Track your courier'
326
+ }) : null
327
+ ]
305
328
  }) : null
306
329
  ]
307
330
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/components/order-status.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { mdiTruckCheckOutline } from '@aglyn/shared-data-mdi'\nimport Alert from '@mui/material/Alert'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Chip from '@mui/material/Chip'\nimport CircularProgress from '@mui/material/CircularProgress'\nimport Divider from '@mui/material/Divider'\nimport Link from '@mui/material/Link'\nimport Paper from '@mui/material/Paper'\nimport Stack from '@mui/material/Stack'\nimport Step from '@mui/material/Step'\nimport StepLabel from '@mui/material/StepLabel'\nimport Stepper from '@mui/material/Stepper'\nimport Typography from '@mui/material/Typography'\nimport { forwardRef, useEffect, useState } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { ORDER_STATUS_COMPONENT_ID } from '../constants/order-status'\nimport {\n formatOrderMoney,\n type OrderStatusView,\n} from '../model'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = ORDER_STATUS_COMPONENT_ID\n\nexport interface OrderStatusProps {\n heading?: string\n}\n\ntype LoadState =\n | { kind: 'loading' }\n | { kind: 'missing'; message: string }\n | { kind: 'ready'; view: OrderStatusView }\n\nfunction dateLabel(atMs: number | null): string {\n if (!atMs) return ''\n return new Date(atMs).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })\n}\n\n/**\n * The guest order-status page (AGL-3610): what a buyer sees when they open\n * the \"View your order\" link in any order email. The commerce page resolver\n * serves it at `/order-status` inside the site's own header and footer; a\n * merchant can also place it on a page of their own design at that address.\n *\n * The order is read AFTER hydration from `?o=&t=` — the page itself is the\n * same for every buyer and may be cached, the order never is — through\n * `/api/commerce/order-status`, which verifies the signed link and returns an\n * allow-listed projection (no email, phone or address).\n */\nconst OrderStatus = forwardRef<HTMLDivElement, OrderStatusProps>((props, ref) => {\n const { heading, ...rest } = props\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { hostId } = Aglyn.useSite()\n const siteFetch = Aglyn.useSiteFetch()\n const [state, setState] = useState<LoadState>({ kind: 'loading' })\n\n useEffect(() => {\n if (!hostId) return\n const params = new URLSearchParams(window.location.search)\n const orderId = params.get('o') ?? ''\n const token = params.get('t') ?? ''\n if (!orderId || !token) {\n setState({\n kind: 'missing',\n message: 'Open this page from the link in your order email.',\n })\n return\n }\n let live = true\n siteFetch(\n `/api/commerce/order-status?hostId=${encodeURIComponent(hostId)}` +\n `&o=${encodeURIComponent(orderId)}&t=${encodeURIComponent(token)}`,\n )\n .then(async (response) => {\n const payload = await response.json().catch(() => ({}))\n if (!live) return\n if (!response.ok) {\n setState({\n kind: 'missing',\n message: String(payload?.error ?? 'We could not find that order.'),\n })\n return\n }\n setState({ kind: 'ready', view: payload as OrderStatusView })\n })\n .catch(() => {\n if (live) {\n setState({\n kind: 'missing',\n message: 'Your order could not be loaded. Check your connection and try again.',\n })\n }\n })\n return () => {\n live = false\n }\n }, [hostId, siteFetch])\n\n if (!hostId) {\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[\n { p: 3, border: '1px dashed', borderColor: 'divider', borderRadius: 1 },\n ...nodeSx,\n ]}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Order status — a buyer’s order, shipments and tracking render here'}\n </Typography>\n </Box>\n )\n }\n\n if (state.kind === 'loading') {\n return (\n <Box ref={ref} {...rest} sx={[{ py: 6, textAlign: 'center' }, ...nodeSx]}>\n <CircularProgress size={28} aria-label=\"Loading your order\" />\n </Box>\n )\n }\n\n if (state.kind === 'missing') {\n return (\n <Box ref={ref} {...rest} sx={[{ maxWidth: 560 }, ...nodeSx]}>\n <Typography variant=\"h4\" component=\"h1\" gutterBottom>\n {heading || 'Your order'}\n </Typography>\n <Alert severity=\"info\">{state.message}</Alert>\n </Box>\n )\n }\n\n const { view } = state\n const money = (cents: number) => formatOrderMoney(cents, view.currency)\n const activeStep = Math.max(\n 0,\n view.steps.reduce((last, step, index) => (step.done ? index : last), 0),\n )\n const cancelled = view.status === 'cancelled'\n\n return (\n <Box ref={ref} {...rest} sx={[{ maxWidth: 720 }, ...nodeSx]}>\n <Stack spacing={3}>\n <Stack spacing={1}>\n {view.storeName ? (\n <Typography variant=\"overline\" color=\"text.secondary\">\n {view.storeName}\n </Typography>\n ) : null}\n <Stack direction=\"row\" spacing={1.5} sx={{ alignItems: 'center', flexWrap: 'wrap' }}>\n <Typography variant=\"h4\" component=\"h1\">\n {heading || `Order ${view.number}`}\n </Typography>\n <Chip\n label={view.statusLabel}\n color={cancelled || view.status === 'refunded' ? 'default' : 'primary'}\n size=\"small\"\n />\n </Stack>\n {view.createdAtMs ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Placed ${dateLabel(view.createdAtMs)}`}\n </Typography>\n ) : null}\n </Stack>\n\n <Stepper activeStep={activeStep} alternativeLabel>\n {view.steps.map((step) => (\n <Step key={step.key} completed={step.done}>\n <StepLabel\n optional={\n step.atMs ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {dateLabel(step.atMs)}\n </Typography>\n ) : undefined\n }\n >\n {step.label}\n </StepLabel>\n </Step>\n ))}\n </Stepper>\n\n {/* Where to collect it, or when it is coming (AGL-3624). */}\n {view.pickup ? (\n <Paper variant=\"outlined\" sx={{ p: 2 }}>\n <Stack spacing={0.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {view.pickup.status === 'picked_up' ? 'Picked up' : 'Pickup'}\n </Typography>\n <Typography variant=\"body2\">\n {[view.pickup.locationName, view.pickup.address].filter(Boolean).join(', ')}\n </Typography>\n {view.pickup.status === 'preparing' ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'We’re preparing your order and will email you when it’s ready.'}\n </Typography>\n ) : null}\n {view.pickup.hours && view.pickup.status !== 'picked_up' ? (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ whiteSpace: 'pre-line' }}>\n {view.pickup.hours}\n </Typography>\n ) : null}\n {view.pickup.instructions && view.pickup.status !== 'picked_up' ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {view.pickup.instructions}\n </Typography>\n ) : null}\n </Stack>\n </Paper>\n ) : null}\n {view.localDelivery ? (\n <Paper variant=\"outlined\" sx={{ p: 2 }}>\n <Stack spacing={0.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Local delivery'}\n </Typography>\n <Typography variant=\"body2\">{view.localDelivery.statusLabel}</Typography>\n {view.localDelivery.windowLabel ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {view.localDelivery.windowLabel}\n </Typography>\n ) : null}\n </Stack>\n </Paper>\n ) : null}\n\n {view.shipments.length ? (\n <Stack spacing={1.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {view.shipments.length === 1 ? 'Shipment' : 'Shipments'}\n </Typography>\n {view.shipments.map((shipment, index) => (\n <Paper key={shipment.id || index} variant=\"outlined\" sx={{ p: 2 }}>\n <Stack spacing={1}>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap' }}\n >\n <Typography variant=\"subtitle2\">\n {[\n view.shipments.length > 1 ? `Package ${index + 1}` : 'Package',\n dateLabel(shipment.atMs) ? `shipped ${dateLabel(shipment.atMs)}` : '',\n ]\n .filter(Boolean)\n .join(' · ')}\n </Typography>\n {shipment.trackingUrl ? (\n <Button\n size=\"small\"\n variant=\"outlined\"\n href={shipment.trackingUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {'Track package'}\n </Button>\n ) : null}\n </Stack>\n {shipment.trackingNumber ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {[shipment.carrier, shipment.trackingNumber].filter(Boolean).join(' ')}\n </Typography>\n ) : null}\n <Typography variant=\"body2\">\n {shipment.lines.map((line) => `${line.quantity}× ${line.name}`).join(', ')}\n </Typography>\n </Stack>\n </Paper>\n ))}\n </Stack>\n ) : null}\n\n <Stack spacing={1}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Items'}\n </Typography>\n {view.lines.map((line, index) => (\n <Stack key={index} direction=\"row\" spacing={2} sx={{ justifyContent: 'space-between' }}>\n <Box>\n <Typography\n variant=\"body2\"\n sx={line.refunded ? { textDecoration: 'line-through' } : undefined}\n >\n {`${line.quantity}× ${line.name}`}\n {line.variantLabel ? ` (${line.variantLabel})` : ''}\n </Typography>\n {line.refunded ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Refunded'}\n </Typography>\n ) : !cancelled && line.shippedQuantity > 0 && line.shippedQuantity < line.quantity ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${line.shippedQuantity} of ${line.quantity} shipped`}\n </Typography>\n ) : null}\n </Box>\n <Typography variant=\"body2\">{money(line.amountCents)}</Typography>\n </Stack>\n ))}\n <Divider />\n {(\n [\n ['Subtotal', view.totals.itemsCents],\n ['Discount', -view.totals.discountCents],\n ['Shipping', view.totals.shippingCents],\n // Optional lines the buyer took at checkout (AGL-3635), by name.\n ...(view.extras ?? []).map((extra) => [extra.label, extra.amountCents]),\n ['Tax', view.totals.taxCents],\n ] as Array<[string, number]>\n )\n .filter(([label, cents]) => label === 'Subtotal' || cents !== 0)\n .map(([label, cents]) => (\n <Stack key={label} direction=\"row\" sx={{ justifyContent: 'space-between' }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {label}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {money(cents)}\n </Typography>\n </Stack>\n ))}\n <Stack direction=\"row\" sx={{ justifyContent: 'space-between' }}>\n <Typography variant=\"subtitle1\">{'Total'}</Typography>\n <Typography variant=\"subtitle1\">{money(view.totals.totalCents)}</Typography>\n </Stack>\n {view.totals.refundedCents > 0 ? (\n <Stack direction=\"row\" sx={{ justifyContent: 'space-between' }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Refunded'}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {money(-view.totals.refundedCents)}\n </Typography>\n </Stack>\n ) : null}\n </Stack>\n\n {view.actions.length ? (\n <Stack direction=\"row\" spacing={1} sx={{ flexWrap: 'wrap' }}>\n {view.actions.map((action) => (\n <Button key={action.id} variant=\"outlined\" href={action.url}>\n {action.label}\n </Button>\n ))}\n </Stack>\n ) : null}\n\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Questions about your order? Reply to your order email'}\n {view.storeName ? ` or contact ${view.storeName}` : ''}\n {'.'}\n </Typography>\n <Link href=\"/\" variant=\"body2\">\n {'Continue shopping'}\n </Link>\n </Stack>\n </Box>\n )\n})\nOrderStatus.displayName = 'OrderStatus'\n\nexport const schema: Aglyn.ComponentSchema<OrderStatusProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Order status',\n description:\n 'A buyer’s order, shipments and tracking, opened from the link in their order emails.',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiTruckCheckOutline.path, sx: { color: 'success.main' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'heading',\n label: 'Heading',\n description: 'Shown above the order. Defaults to the order number.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Order status',\n pluginId: BUNDLE_ID,\n description: 'The buyer’s order status, for the /order-status page',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiTruckCheckOutline.path, sx: { color: 'success.main' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n]\n\nexport default OrderStatus\n"],"names":["Aglyn","mdiTruckCheckOutline","Alert","Box","Button","Chip","CircularProgress","Divider","Link","Paper","Stack","Step","StepLabel","Stepper","Typography","forwardRef","useEffect","useState","BUNDLE_ID","ORDER_STATUS_COMPONENT_ID","formatOrderMoney","generatePresetId","ID","dateLabel","atMs","Date","toLocaleDateString","undefined","month","day","year","OrderStatus","props","ref","view","heading","rest","nodeSx","Array","isArray","hostId","useSite","siteFetch","useSiteFetch","state","setState","kind","params","URLSearchParams","window","location","search","orderId","get","token","message","live","encodeURIComponent","then","response","payload","json","catch","ok","String","error","sx","p","border","borderColor","borderRadius","variant","color","py","textAlign","size","aria-label","maxWidth","component","gutterBottom","severity","money","cents","currency","activeStep","Math","max","steps","reduce","last","step","index","done","cancelled","status","spacing","storeName","direction","alignItems","flexWrap","number","label","statusLabel","createdAtMs","alternativeLabel","map","completed","optional","key","pickup","locationName","address","filter","Boolean","join","hours","whiteSpace","instructions","localDelivery","windowLabel","shipments","length","shipment","justifyContent","trackingUrl","href","target","rel","trackingNumber","carrier","lines","line","quantity","name","id","refunded","textDecoration","variantLabel","shippedQuantity","amountCents","totals","itemsCents","discountCents","shippingCents","extras","extra","taxCents","totalCents","refundedCents","actions","action","url","displayName","schema","$id","pluginId","description","category","ComponentCategory","COMMERCE","icon","path","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","FieldComponentType","TEXT_FIELD","presets","type","NodeType","PRESET","data","componentId"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/components/order-status.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { mdiTruckCheckOutline } from '@aglyn/shared-data-mdi'\nimport Alert from '@mui/material/Alert'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Chip from '@mui/material/Chip'\nimport CircularProgress from '@mui/material/CircularProgress'\nimport Divider from '@mui/material/Divider'\nimport Link from '@mui/material/Link'\nimport Paper from '@mui/material/Paper'\nimport Stack from '@mui/material/Stack'\nimport Step from '@mui/material/Step'\nimport StepLabel from '@mui/material/StepLabel'\nimport Stepper from '@mui/material/Stepper'\nimport Typography from '@mui/material/Typography'\nimport { forwardRef, useEffect, useState } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { ORDER_STATUS_COMPONENT_ID } from '../constants/order-status'\nimport {\n formatOrderMoney,\n type OrderStatusView,\n} from '../model'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = ORDER_STATUS_COMPONENT_ID\n\nexport interface OrderStatusProps {\n heading?: string\n}\n\ntype LoadState =\n | { kind: 'loading' }\n | { kind: 'missing'; message: string }\n | { kind: 'ready'; view: OrderStatusView }\n\nfunction dateLabel(atMs: number | null): string {\n if (!atMs) return ''\n return new Date(atMs).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })\n}\n\n/**\n * The guest order-status page (AGL-3610): what a buyer sees when they open\n * the \"View your order\" link in any order email. The commerce page resolver\n * serves it at `/order-status` inside the site's own header and footer; a\n * merchant can also place it on a page of their own design at that address.\n *\n * The order is read AFTER hydration from `?o=&t=` — the page itself is the\n * same for every buyer and may be cached, the order never is — through\n * `/api/commerce/order-status`, which verifies the signed link and returns an\n * allow-listed projection (no email, phone or address).\n */\nconst OrderStatus = forwardRef<HTMLDivElement, OrderStatusProps>((props, ref) => {\n const { heading, ...rest } = props\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { hostId } = Aglyn.useSite()\n const siteFetch = Aglyn.useSiteFetch()\n const [state, setState] = useState<LoadState>({ kind: 'loading' })\n\n useEffect(() => {\n if (!hostId) return\n const params = new URLSearchParams(window.location.search)\n const orderId = params.get('o') ?? ''\n const token = params.get('t') ?? ''\n if (!orderId || !token) {\n setState({\n kind: 'missing',\n message: 'Open this page from the link in your order email.',\n })\n return\n }\n let live = true\n siteFetch(\n `/api/commerce/order-status?hostId=${encodeURIComponent(hostId)}` +\n `&o=${encodeURIComponent(orderId)}&t=${encodeURIComponent(token)}`,\n )\n .then(async (response) => {\n const payload = await response.json().catch(() => ({}))\n if (!live) return\n if (!response.ok) {\n setState({\n kind: 'missing',\n message: String(payload?.error ?? 'We could not find that order.'),\n })\n return\n }\n setState({ kind: 'ready', view: payload as OrderStatusView })\n })\n .catch(() => {\n if (live) {\n setState({\n kind: 'missing',\n message: 'Your order could not be loaded. Check your connection and try again.',\n })\n }\n })\n return () => {\n live = false\n }\n }, [hostId, siteFetch])\n\n if (!hostId) {\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[\n { p: 3, border: '1px dashed', borderColor: 'divider', borderRadius: 1 },\n ...nodeSx,\n ]}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Order status — a buyer’s order, shipments and tracking render here'}\n </Typography>\n </Box>\n )\n }\n\n if (state.kind === 'loading') {\n return (\n <Box ref={ref} {...rest} sx={[{ py: 6, textAlign: 'center' }, ...nodeSx]}>\n <CircularProgress size={28} aria-label=\"Loading your order\" />\n </Box>\n )\n }\n\n if (state.kind === 'missing') {\n return (\n <Box ref={ref} {...rest} sx={[{ maxWidth: 560 }, ...nodeSx]}>\n <Typography variant=\"h4\" component=\"h1\" gutterBottom>\n {heading || 'Your order'}\n </Typography>\n <Alert severity=\"info\">{state.message}</Alert>\n </Box>\n )\n }\n\n const { view } = state\n const money = (cents: number) => formatOrderMoney(cents, view.currency)\n const activeStep = Math.max(\n 0,\n view.steps.reduce((last, step, index) => (step.done ? index : last), 0),\n )\n const cancelled = view.status === 'cancelled'\n\n return (\n <Box ref={ref} {...rest} sx={[{ maxWidth: 720 }, ...nodeSx]}>\n <Stack spacing={3}>\n <Stack spacing={1}>\n {view.storeName ? (\n <Typography variant=\"overline\" color=\"text.secondary\">\n {view.storeName}\n </Typography>\n ) : null}\n <Stack direction=\"row\" spacing={1.5} sx={{ alignItems: 'center', flexWrap: 'wrap' }}>\n <Typography variant=\"h4\" component=\"h1\">\n {heading || `Order ${view.number}`}\n </Typography>\n <Chip\n label={view.statusLabel}\n color={cancelled || view.status === 'refunded' ? 'default' : 'primary'}\n size=\"small\"\n />\n </Stack>\n {view.createdAtMs ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Placed ${dateLabel(view.createdAtMs)}`}\n </Typography>\n ) : null}\n </Stack>\n\n <Stepper activeStep={activeStep} alternativeLabel>\n {view.steps.map((step) => (\n <Step key={step.key} completed={step.done}>\n <StepLabel\n optional={\n step.atMs ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {dateLabel(step.atMs)}\n </Typography>\n ) : undefined\n }\n >\n {step.label}\n </StepLabel>\n </Step>\n ))}\n </Stepper>\n\n {/* Where to collect it, or when it is coming (AGL-3624). */}\n {view.pickup ? (\n <Paper variant=\"outlined\" sx={{ p: 2 }}>\n <Stack spacing={0.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {view.pickup.status === 'picked_up' ? 'Picked up' : 'Pickup'}\n </Typography>\n <Typography variant=\"body2\">\n {[view.pickup.locationName, view.pickup.address].filter(Boolean).join(', ')}\n </Typography>\n {view.pickup.status === 'preparing' ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'We’re preparing your order and will email you when it’s ready.'}\n </Typography>\n ) : null}\n {view.pickup.hours && view.pickup.status !== 'picked_up' ? (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ whiteSpace: 'pre-line' }}>\n {view.pickup.hours}\n </Typography>\n ) : null}\n {view.pickup.instructions && view.pickup.status !== 'picked_up' ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {view.pickup.instructions}\n </Typography>\n ) : null}\n </Stack>\n </Paper>\n ) : null}\n {view.localDelivery ? (\n <Paper variant=\"outlined\" sx={{ p: 2 }}>\n <Stack spacing={0.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Local delivery'}\n </Typography>\n <Typography variant=\"body2\">{view.localDelivery.statusLabel}</Typography>\n {view.localDelivery.windowLabel ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {view.localDelivery.windowLabel}\n </Typography>\n ) : null}\n {view.localDelivery.courier ? (\n <>\n <Typography variant=\"body2\">\n {`${view.localDelivery.courier.providerLabel}: ${view.localDelivery.courier.stateLabel}`}\n </Typography>\n {view.localDelivery.courier.etaMs ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Arriving about ${new Date(view.localDelivery.courier.etaMs).toLocaleTimeString([], {\n hour: 'numeric',\n minute: '2-digit',\n })}`}\n </Typography>\n ) : null}\n {view.localDelivery.courier.trackingUrl ? (\n <Link\n href={view.localDelivery.courier.trackingUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n variant=\"body2\"\n >\n {'Track your courier'}\n </Link>\n ) : null}\n </>\n ) : null}\n </Stack>\n </Paper>\n ) : null}\n\n {view.shipments.length ? (\n <Stack spacing={1.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {view.shipments.length === 1 ? 'Shipment' : 'Shipments'}\n </Typography>\n {view.shipments.map((shipment, index) => (\n <Paper key={shipment.id || index} variant=\"outlined\" sx={{ p: 2 }}>\n <Stack spacing={1}>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap' }}\n >\n <Typography variant=\"subtitle2\">\n {[\n view.shipments.length > 1 ? `Package ${index + 1}` : 'Package',\n dateLabel(shipment.atMs) ? `shipped ${dateLabel(shipment.atMs)}` : '',\n ]\n .filter(Boolean)\n .join(' · ')}\n </Typography>\n {shipment.trackingUrl ? (\n <Button\n size=\"small\"\n variant=\"outlined\"\n href={shipment.trackingUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {'Track package'}\n </Button>\n ) : null}\n </Stack>\n {shipment.trackingNumber ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {[shipment.carrier, shipment.trackingNumber].filter(Boolean).join(' ')}\n </Typography>\n ) : null}\n <Typography variant=\"body2\">\n {shipment.lines.map((line) => `${line.quantity}× ${line.name}`).join(', ')}\n </Typography>\n </Stack>\n </Paper>\n ))}\n </Stack>\n ) : null}\n\n <Stack spacing={1}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Items'}\n </Typography>\n {view.lines.map((line, index) => (\n <Stack key={index} direction=\"row\" spacing={2} sx={{ justifyContent: 'space-between' }}>\n <Box>\n <Typography\n variant=\"body2\"\n sx={line.refunded ? { textDecoration: 'line-through' } : undefined}\n >\n {`${line.quantity}× ${line.name}`}\n {line.variantLabel ? ` (${line.variantLabel})` : ''}\n </Typography>\n {line.refunded ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Refunded'}\n </Typography>\n ) : !cancelled && line.shippedQuantity > 0 && line.shippedQuantity < line.quantity ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${line.shippedQuantity} of ${line.quantity} shipped`}\n </Typography>\n ) : null}\n </Box>\n <Typography variant=\"body2\">{money(line.amountCents)}</Typography>\n </Stack>\n ))}\n <Divider />\n {(\n [\n ['Subtotal', view.totals.itemsCents],\n ['Discount', -view.totals.discountCents],\n ['Shipping', view.totals.shippingCents],\n // Optional lines the buyer took at checkout (AGL-3635), by name.\n ...(view.extras ?? []).map((extra) => [extra.label, extra.amountCents]),\n ['Tax', view.totals.taxCents],\n ] as Array<[string, number]>\n )\n .filter(([label, cents]) => label === 'Subtotal' || cents !== 0)\n .map(([label, cents]) => (\n <Stack key={label} direction=\"row\" sx={{ justifyContent: 'space-between' }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {label}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {money(cents)}\n </Typography>\n </Stack>\n ))}\n <Stack direction=\"row\" sx={{ justifyContent: 'space-between' }}>\n <Typography variant=\"subtitle1\">{'Total'}</Typography>\n <Typography variant=\"subtitle1\">{money(view.totals.totalCents)}</Typography>\n </Stack>\n {view.totals.refundedCents > 0 ? (\n <Stack direction=\"row\" sx={{ justifyContent: 'space-between' }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Refunded'}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {money(-view.totals.refundedCents)}\n </Typography>\n </Stack>\n ) : null}\n </Stack>\n\n {view.actions.length ? (\n <Stack direction=\"row\" spacing={1} sx={{ flexWrap: 'wrap' }}>\n {view.actions.map((action) => (\n <Button key={action.id} variant=\"outlined\" href={action.url}>\n {action.label}\n </Button>\n ))}\n </Stack>\n ) : null}\n\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Questions about your order? Reply to your order email'}\n {view.storeName ? ` or contact ${view.storeName}` : ''}\n {'.'}\n </Typography>\n <Link href=\"/\" variant=\"body2\">\n {'Continue shopping'}\n </Link>\n </Stack>\n </Box>\n )\n})\nOrderStatus.displayName = 'OrderStatus'\n\nexport const schema: Aglyn.ComponentSchema<OrderStatusProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Order status',\n description:\n 'A buyer’s order, shipments and tracking, opened from the link in their order emails.',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiTruckCheckOutline.path, sx: { color: 'success.main' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'heading',\n label: 'Heading',\n description: 'Shown above the order. Defaults to the order number.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Order status',\n pluginId: BUNDLE_ID,\n description: 'The buyer’s order status, for the /order-status page',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiTruckCheckOutline.path, sx: { color: 'success.main' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n]\n\nexport default OrderStatus\n"],"names":["Aglyn","mdiTruckCheckOutline","Alert","Box","Button","Chip","CircularProgress","Divider","Link","Paper","Stack","Step","StepLabel","Stepper","Typography","forwardRef","useEffect","useState","BUNDLE_ID","ORDER_STATUS_COMPONENT_ID","formatOrderMoney","generatePresetId","ID","dateLabel","atMs","Date","toLocaleDateString","undefined","month","day","year","OrderStatus","props","ref","view","heading","rest","nodeSx","Array","isArray","hostId","useSite","siteFetch","useSiteFetch","state","setState","kind","params","URLSearchParams","window","location","search","orderId","get","token","message","live","encodeURIComponent","then","response","payload","json","catch","ok","String","error","sx","p","border","borderColor","borderRadius","variant","color","py","textAlign","size","aria-label","maxWidth","component","gutterBottom","severity","money","cents","currency","activeStep","Math","max","steps","reduce","last","step","index","done","cancelled","status","spacing","storeName","direction","alignItems","flexWrap","number","label","statusLabel","createdAtMs","alternativeLabel","map","completed","optional","key","pickup","locationName","address","filter","Boolean","join","hours","whiteSpace","instructions","localDelivery","windowLabel","courier","providerLabel","stateLabel","etaMs","toLocaleTimeString","hour","minute","trackingUrl","href","target","rel","shipments","length","shipment","justifyContent","trackingNumber","carrier","lines","line","quantity","name","id","refunded","textDecoration","variantLabel","shippedQuantity","amountCents","totals","itemsCents","discountCents","shippingCents","extras","extra","taxCents","totalCents","refundedCents","actions","action","url","displayName","schema","$id","pluginId","description","category","ComponentCategory","COMMERCE","icon","path","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","FieldComponentType","TEXT_FIELD","presets","type","NodeType","PRESET","data","componentId"],"mappings":"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"}
@@ -16,7 +16,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
16
16
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
17
  * See the License for the specific language governing permissions and
18
18
  * limitations under the License.
19
- */ import * as Aglyn from "@aglyn/aglyn";
19
+ */ import { advertisingConsentField } from "@aglyn/aglyn/app-utils/advertising-consent";
20
+ import * as Aglyn from "@aglyn/aglyn";
20
21
  import { buildAddToCartParams, buildBeginCheckoutParams, trackEvent, trackEventBeforeNavigation } from "@aglyn/aglyn/app-utils/analytics-events";
21
22
  import { recordSiteJourneyStep } from "@aglyn/aglyn/app-utils/site-journey";
22
23
  import { isPaymentsNotConfigured } from "@aglyn/aglyn/app-utils/payments-configured";
@@ -55,6 +56,7 @@ import { CheckoutReturnNotice } from "./checkout-return-notice.js";
55
56
  })));
56
57
  // Component ids are persisted in screen documents; never rename.
57
58
  export const ID = 'product-detail';
59
+ /** What the page says where a variant with no price yet would show one (AGL-3676). */ const PRICE_COMING_SOON_LABEL = 'Price coming soon';
58
60
  const SAMPLE = {
59
61
  id: 'sample',
60
62
  name: 'Sample product',
@@ -110,10 +112,11 @@ const SAMPLE = {
110
112
  * payload — the same figure `checkout` prices the charge from, so the reported
111
113
  * value and the amount Stripe collects come from one source.
112
114
  */ function buyItem(product, variant, quantity) {
115
+ var _ref;
113
116
  return {
114
117
  item_id: product.id,
115
118
  item_name: product.name,
116
- price: variant == null ? void 0 : variant.priceUsd,
119
+ price: (_ref = variant == null ? void 0 : variant.priceUsd) != null ? _ref : undefined,
117
120
  quantity
118
121
  };
119
122
  }
@@ -129,7 +132,7 @@ function slugFromLocation() {
129
132
  * variant. Resolves its product from the /products/{slug} URL unless a
130
133
  * slug prop pins it; sample data on the inert canvas.
131
134
  */ const ProductDetail = /*#__PURE__*/ forwardRef((props, ref)=>{
132
- var _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6;
135
+ var _ref, _ref1, _ref2;
133
136
  var _site_pageData_commerce, _site_pageData;
134
137
  const { slug: slugProp, buyLabel, hideDescription, showCoupon } = props, rest = _object_without_properties_loose(props, [
135
138
  "slug",
@@ -350,7 +353,7 @@ function slugFromLocation() {
350
353
  fulfillment: fulfillment.request
351
354
  } : {}, coupon.trim() ? {
352
355
  couponCode: coupon.trim()
353
- } : {}))
356
+ } : {}, advertisingConsentField(hostId)))
354
357
  });
355
358
  const payload = await response.json().catch(()=>({}));
356
359
  // In-page payment (AGL-1944). A native session returns a client secret
@@ -508,6 +511,9 @@ function slugFromLocation() {
508
511
  const subscription = resolved.subscription;
509
512
  const intervalSuffix = (subscription == null ? void 0 : subscription.interval) === 'year' ? '/yr' : '/mo';
510
513
  const subscribing = Boolean(subscription) && (!resolved.subscriptionOptional || billing === 'subscribe');
514
+ // Listed before it has a price (AGL-3676): no price to show and nothing
515
+ // to buy; every sale door would refuse it anyway.
516
+ const priced = typeof (variant == null ? void 0 : variant.priceUsd) === 'number';
511
517
  // schema.org Product/Offer (AGL-299). Kept ONLY for the case where this
512
518
  // block renders without server-seeded page data — the besigner preview,
513
519
  // or a page whose resolver didn't supply it. When the tenant page seeds
@@ -521,14 +527,14 @@ function slugFromLocation() {
521
527
  description: resolved.description
522
528
  } : {}, resolved.mediaUrls.length ? {
523
529
  image: resolved.mediaUrls
524
- } : {}, {
530
+ } : {}, priced ? {
525
531
  offers: {
526
532
  '@type': 'Offer',
527
533
  priceCurrency: 'USD',
528
- price: String((_ref3 = variant == null ? void 0 : variant.priceUsd) != null ? _ref3 : 0),
534
+ price: String(variant == null ? void 0 : variant.priceUsd),
529
535
  availability: (variant == null ? void 0 : variant.soldOut) ? 'https://schema.org/OutOfStock' : 'https://schema.org/InStock'
530
536
  }
531
- }) : null;
537
+ } : {}) : null;
532
538
  return /*#__PURE__*/ _jsxs(Box, _extends({
533
539
  ref: ref
534
540
  }, rest, {
@@ -642,7 +648,7 @@ function slugFromLocation() {
642
648
  children: [
643
649
  /*#__PURE__*/ _jsx(Typography, {
644
650
  variant: "h6",
645
- children: `$${(_ref4 = variant == null ? void 0 : variant.priceUsd) != null ? _ref4 : 0}${subscribing ? intervalSuffix : ''}`
651
+ children: priced ? `$${variant == null ? void 0 : variant.priceUsd}${subscribing ? intervalSuffix : ''}` : PRICE_COMING_SOON_LABEL
646
652
  }),
647
653
  subscribing && (subscription == null ? void 0 : subscription.trialDays) ? /*#__PURE__*/ _jsx(Typography, {
648
654
  variant: "caption",
@@ -697,11 +703,11 @@ function slugFromLocation() {
697
703
  children: [
698
704
  /*#__PURE__*/ _jsx(ToggleButton, {
699
705
  value: "once",
700
- children: `One-time $${(_ref5 = variant == null ? void 0 : variant.priceUsd) != null ? _ref5 : 0}`
706
+ children: priced ? `One-time $${variant == null ? void 0 : variant.priceUsd}` : 'One-time'
701
707
  }),
702
708
  /*#__PURE__*/ _jsx(ToggleButton, {
703
709
  value: "subscribe",
704
- children: `Subscribe $${(_ref6 = variant == null ? void 0 : variant.priceUsd) != null ? _ref6 : 0}${intervalSuffix}`
710
+ children: priced ? `Subscribe $${variant == null ? void 0 : variant.priceUsd}${intervalSuffix}` : 'Subscribe'
705
711
  })
706
712
  ]
707
713
  }) : null,
@@ -735,9 +741,17 @@ function slugFromLocation() {
735
741
  display: 'block'
736
742
  }
737
743
  }) : null,
744
+ !priced ? /*#__PURE__*/ _jsx(Typography, {
745
+ variant: "body2",
746
+ color: "text.secondary",
747
+ sx: {
748
+ mb: 2
749
+ },
750
+ children: 'Not on sale yet — check back soon.'
751
+ }) : null,
738
752
  /*#__PURE__*/ _jsxs(Box, {
739
753
  sx: {
740
- display: 'flex',
754
+ display: priced ? 'flex' : 'none',
741
755
  gap: 1.5,
742
756
  alignItems: 'center',
743
757
  mb: 2
@@ -761,7 +775,7 @@ function slugFromLocation() {
761
775
  variant: "outlined",
762
776
  color: "primary",
763
777
  size: "large",
764
- disabled: !hostId || (variant == null ? void 0 : variant.soldOut),
778
+ disabled: !hostId || !priced || (variant == null ? void 0 : variant.soldOut),
765
779
  onClick: handleAddToCart,
766
780
  children: added ? 'Added ✓' : 'Add to cart'
767
781
  }),
@@ -769,7 +783,7 @@ function slugFromLocation() {
769
783
  variant: "contained",
770
784
  color: "primary",
771
785
  size: "large",
772
- disabled: !hostId || status === 'sending' || (variant == null ? void 0 : variant.soldOut) || // No payments on this deployment: the same 501 every time, so
786
+ disabled: !hostId || !priced || status === 'sending' || (variant == null ? void 0 : variant.soldOut) || // No payments on this deployment: the same 501 every time, so
773
787
  // the control latches off rather than inviting a retry that
774
788
  // cannot succeed (AGL-2019).
775
789
  status === 'unconfigured' || // Asked but unanswered: the server would only refuse again.
@@ -806,7 +820,7 @@ function slugFromLocation() {
806
820
  onCancel: ()=>setNativeCheckout(null)
807
821
  })
808
822
  }) : null,
809
- fulfillment.offered ? /*#__PURE__*/ _jsx(Box, {
823
+ fulfillment.offered && priced ? /*#__PURE__*/ _jsx(Box, {
810
824
  sx: {
811
825
  mb: 2
812
826
  },
@@ -815,7 +829,7 @@ function slugFromLocation() {
815
829
  formatCents: (cents)=>`$${(cents / 100).toFixed(2)}`
816
830
  })
817
831
  }) : null,
818
- shipCountries && fulfillment.method === 'shipping' ? /*#__PURE__*/ _jsx(TextField, {
832
+ shipCountries && fulfillment.method === 'shipping' && priced ? /*#__PURE__*/ _jsx(TextField, {
819
833
  select: true,
820
834
  label: "Ship to",
821
835
  value: shipTo,
@@ -834,7 +848,7 @@ function slugFromLocation() {
834
848
  }, code);
835
849
  })
836
850
  }) : null,
837
- askPostal && fulfillment.method === 'shipping' ? /*#__PURE__*/ _jsx(TextField, {
851
+ askPostal && fulfillment.method === 'shipping' && priced ? /*#__PURE__*/ _jsx(TextField, {
838
852
  label: "Postal code",
839
853
  value: shipPostal,
840
854
  onChange: (event)=>setShipPostal(event.target.value),