@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.
- package/package.json +13 -13
- package/src/lib/components/cart.js +3 -2
- package/src/lib/components/cart.js.map +1 -1
- package/src/lib/components/console/commerce-analytics-card.component.js +3 -6
- package/src/lib/components/console/commerce-analytics-card.component.js.map +1 -1
- package/src/lib/components/console/commerce-glance-card.component.js +9 -3
- package/src/lib/components/console/commerce-glance-card.component.js.map +1 -1
- package/src/lib/components/console/customer-notifications-card.component.js +3 -1
- package/src/lib/components/console/customer-notifications-card.component.js.map +1 -1
- package/src/lib/components/console/discounts-card.component.js +2 -3
- package/src/lib/components/console/discounts-card.component.js.map +1 -1
- package/src/lib/components/console/host-coupons-card.component.js +3 -4
- package/src/lib/components/console/host-coupons-card.component.js.map +1 -1
- package/src/lib/components/console/local-delivery-settings-card.component.js +2 -2
- package/src/lib/components/console/local-delivery-settings-card.component.js.map +1 -1
- package/src/lib/components/console/locations-card.component.js +1 -1
- package/src/lib/components/console/locations-card.component.js.map +1 -1
- package/src/lib/components/console/member-posts-card.component.js +2 -2
- package/src/lib/components/console/member-posts-card.component.js.map +1 -1
- package/src/lib/components/console/order-detail-dialog.component.js +35 -30
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/order-fulfillment-panel.component.d.ts +11 -1
- package/src/lib/components/console/order-fulfillment-panel.component.js +75 -4
- package/src/lib/components/console/order-fulfillment-panel.component.js.map +1 -1
- package/src/lib/components/console/order-zones.d.ts +45 -1
- package/src/lib/components/console/order-zones.js +8 -0
- package/src/lib/components/console/order-zones.js.map +1 -1
- package/src/lib/components/console/pickup-delivery-queue-card.component.js +15 -1
- package/src/lib/components/console/pickup-delivery-queue-card.component.js.map +1 -1
- package/src/lib/components/console/pos-page.component.js +3 -2
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/product-editor-dialog.component.d.ts +2 -0
- package/src/lib/components/console/product-editor-dialog.component.js +30 -12
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/products-hub-card.component.js +13 -4
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/products-hub-zone.component.d.ts +2 -1
- package/src/lib/components/console/products-hub-zone.component.js +1 -1
- package/src/lib/components/console/products-hub-zone.component.js.map +1 -1
- package/src/lib/components/console/reviews-moderation-card.component.js +1 -2
- package/src/lib/components/console/reviews-moderation-card.component.js.map +1 -1
- package/src/lib/components/console/shipping-settings-card.component.js +2 -2
- package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
- package/src/lib/components/console/shippingeasy-card.component.js +1 -1
- package/src/lib/components/console/shippingeasy-card.component.js.map +1 -1
- package/src/lib/components/console/shipstation-card.component.js +1 -2
- package/src/lib/components/console/shipstation-card.component.js.map +1 -1
- package/src/lib/components/console/store-settings-card.component.js +3 -1
- package/src/lib/components/console/store-settings-card.component.js.map +1 -1
- package/src/lib/components/console/tax-settings-card.component.js +4 -1
- package/src/lib/components/console/tax-settings-card.component.js.map +1 -1
- package/src/lib/components/order-status.js +24 -1
- package/src/lib/components/order-status.js.map +1 -1
- package/src/lib/components/product-detail.js +30 -16
- package/src/lib/components/product-detail.js.map +1 -1
- package/src/lib/components/product-grid.d.ts +7 -0
- package/src/lib/components/product-grid.js +50 -7
- package/src/lib/components/product-grid.js.map +1 -1
- package/src/lib/components/related-products.js +1 -1
- package/src/lib/components/related-products.js.map +1 -1
- package/src/lib/components/wishlist.js +1 -1
- package/src/lib/components/wishlist.js.map +1 -1
- package/src/lib/declarations.server.js +11 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/model/commerce-orders.d.ts +8 -0
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce.d.ts +21 -0
- package/src/lib/model/commerce.js +39 -1
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/index.d.ts +1 -0
- package/src/lib/model/index.js +1 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/order-annotations.d.ts +54 -0
- package/src/lib/model/order-annotations.js +76 -0
- package/src/lib/model/order-annotations.js.map +1 -0
- package/src/lib/model/order-events.d.ts +2 -0
- package/src/lib/model/order-events.js.map +1 -1
- package/src/lib/model/order-fulfillment.d.ts +29 -0
- package/src/lib/model/order-fulfillment.js +63 -0
- package/src/lib/model/order-fulfillment.js.map +1 -1
- package/src/lib/model/order-local-fulfillment.d.ts +36 -0
- package/src/lib/model/order-local-fulfillment.js +19 -1
- package/src/lib/model/order-local-fulfillment.js.map +1 -1
- package/src/lib/model/order-status-view.d.ts +11 -0
- package/src/lib/model/order-status-view.js +20 -3
- package/src/lib/model/order-status-view.js.map +1 -1
- package/src/lib/model/product-write.js +8 -4
- package/src/lib/model/product-write.js.map +1 -1
- package/src/lib/server/api-v1/openapi.js +1 -0
- package/src/lib/server/api-v1/openapi.js.map +1 -1
- package/src/lib/server/api-v1/order-view.d.ts +1 -0
- package/src/lib/server/api-v1/order-view.js +10 -0
- package/src/lib/server/api-v1/order-view.js.map +1 -1
- package/src/lib/server/cart-checkout.js +9 -1
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/catalog.d.ts +6 -0
- package/src/lib/server/catalog.js +3 -1
- package/src/lib/server/catalog.js.map +1 -1
- package/src/lib/server/checkout.js +11 -1
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/fulfill-order.d.ts +12 -0
- package/src/lib/server/fulfill-order.js +13 -0
- package/src/lib/server/fulfill-order.js.map +1 -1
- package/src/lib/server/local-delivery-records.d.ts +30 -0
- package/src/lib/server/local-delivery-records.js +284 -0
- package/src/lib/server/local-delivery-records.js.map +1 -0
- package/src/lib/server/order-annotations.d.ts +28 -0
- package/src/lib/server/order-annotations.js +143 -0
- package/src/lib/server/order-annotations.js.map +1 -0
- package/src/lib/server/order-events.js +2 -1
- package/src/lib/server/order-events.js.map +1 -1
- package/src/lib/server/order-notifications.js +39 -8
- package/src/lib/server/order-notifications.js.map +1 -1
- package/src/lib/server/pos-payment.js +9 -3
- package/src/lib/server/pos-payment.js.map +1 -1
- package/src/lib/server/product-catalog.js +6 -2
- package/src/lib/server/product-catalog.js.map +1 -1
- package/src/lib/server/product-drafts.d.ts +36 -9
- package/src/lib/server/product-drafts.js +24 -5
- package/src/lib/server/product-drafts.js.map +1 -1
- package/src/lib/server/product.d.ts +6 -1
- package/src/lib/server/product.js +1 -1
- package/src/lib/server/product.js.map +1 -1
- package/src/lib/server/products-write.d.ts +29 -0
- package/src/lib/server/products-write.js +7 -7
- package/src/lib/server/products-write.js.map +1 -1
- package/src/lib/server/shipment-records.js +2 -0
- package/src/lib/server/shipment-records.js.map +1 -1
- package/src/lib/server/site-page-resolver.d.ts +13 -0
- package/src/lib/server/site-page-resolver.js +138 -1
- package/src/lib/server/site-page-resolver.js.map +1 -1
- package/src/lib/server.js +5 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/utils/use-storefront-purchase-event.js +8 -2
- 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":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;;AAEA,SAASA,WAAW,QAAQ,uBAAsB;AAClD,SAASC,WAAW,QAAQ,8BAA6B;AACzD,SACEC,MAAM,EACNC,gBAAgB,EAChBC,QAAQ,EACRC,KAAK,EACLC,MAAM,EACNC,SAAS,EACTC,UAAU,QACL,gBAAe;AACtB,SAASC,GAAG,QAAQ,qBAAoB;AACxC,SAASC,WAAW,EAAEC,QAAQ,QAAQ,QAAO;AAC7C,SAASC,YAAY,EAAEC,OAAO,QAAQ,iCAAgC;AACtE,SACEC,eAAe,EACfC,kBAAkB,QACb,iCAAgC;AACvC,SAASC,cAAc,QAAQ,eAAc;AAC7C,SAASC,mBAAmB,QAAQ,gEAA+D;AAiBnG;;;;;CAKC,GACD,OAAO,SAASC,kBAAkBC,KAA6B;iDAyH9CC,sBAkBAA,6BAoBAA,mBAuBAA,mBAQAA;IA7Lf,MAAM,EAAEC,MAAM,EAAE,GAAGF;IACnB,MAAMG,YAAYV;IAClB,MAAM,EAAEW,MAAMC,IAAI,EAAE,GAAGX;IACvB,MAAM,EAAEY,eAAe,EAAE,GAAGxB;IAC5B,MAAM,EACJsB,MAAMG,KAAK,EACXC,QAAQC,WAAW,EACnB;;;;;;;;KAQC,GACDC,WAAWC,cAAc,EAC1B,GAAGhB,gBACF,IAAML,IAAIa,WAAW,SAASD,QAAQ,YAAY,UAClD;QAACC;QAAWD;KAAO;IAErB,MAAM,EAAEE,MAAMQ,IAAI,EAAE,GAAGjB,gBACrB,IAAML,IAAIa,WAAW,SAASD,SAC9B;QAACC;QAAWD;KAAO;IAErB,MAAM,CAACW,OAAOC,SAAS,GAAGtB,SAA+B;IACzD,MAAMS,UAAyBY,gBAAAA,QAAS;QACtCE,WAAW,UAAER,yBAAAA,MAAOQ,WAAW,mBAAI;QACnCC,kBAAkB,WAAET,yBAAAA,MAAOS,kBAAkB,oBAAI;QACjDC,QAAQ,WAAEV,yBAAAA,MAAOU,QAAQ,oBAAI;QAC7BC,eAAeX,CAAAA,yBAAAA,MAAOW,aAAa,MAAK;QACxCC,QAAQ,WAAEZ,yBAAAA,MAAOY,QAAQ,oBAAI;QAC7BC,aAAa,WAAEb,yBAAAA,MAAOa,aAAa,oBAAI;IACzC;IACA,MAAMC,SAAS,CAACC,QACdR,SAAS,aAAKb,SAAYqB;IAE5B,mEAAmE;IACnE,MAAMC,gBAAgBC,OAAOC,OAAO,UACjCb,wBAAAA,KAAMc,OAAO,oBAAI,CAAC,GACnBC,IAAI,CAAC,CAAC,GAAGC,EAAE,EAAE,GAAGC,EAAE,GAAKC,OAAOF,GAAGG,aAAa,CAACD,OAAOD;IAExD,MAAMG,aAAazC,YAAY;QAC7B;;;;;;;;;;;;KAYC,GACD,MAAM0C,UAAU,MAAMrC,mBACpB;YACEsC,SAAS;YACTC,YAAY1B,gBAAgB;YAC5BC,WAAWC;QACb,GACA;YACE,6DAA6D;YAC7D,mEAAmE;YACnE,kDAAkD;YAClD,MAAMb,oBAAoB;gBACxBK;gBACAE;gBACAH;gBACAkC,OAAO,CAACC;wBAMQpC;2BALdoC,MAAMC,GAAG,CACPhD,IAAIa,WAAW,SAASD,QAAQ,YAAY,UAC5C;wBACEa,aAAad,QAAQc,WAAW,IAAI;wBACpCC,oBAAoBf,QAAQe,kBAAkB,IAAI;wBAClDC,QAAQ,GAAEhB,oBAAAA,QAAQgB,QAAQ,YAAhBhB,oBAAoB;wBAC9BiB,eAAejB,QAAQiB,aAAa,KAAK;wBACzCC,UAAUlB,QAAQkB,QAAQ,IAAI;wBAC9BC,eAAenB,QAAQmB,aAAa,IAAI;oBAC1C,GACA;wBAAEmB,OAAO;oBAAK;;YAEpB;QACF;QAEF,mEAAmE;QACnE,mEAAmE;QACnE,4DAA4D;QAC5D,IAAI,CAACN,QAAQO,EAAE,EAAE;YACf,OAAO,KAAKlC,gBAAgB2B,QAAQQ,OAAO,EAAE;gBAC3CC,SAAS;gBACTC,SAAS;YACX;QACF;QACA7B,SAAS;QACTR,gBAAgB,wBAAwB;YACtCoC,SAAS;YACTC,SAAS;QACX;IACF,GAAG;QACD1C;QACAE;QACAD;QACAG;QACAC;QACAG;QACAE;KACD;IAED,qBACE,KAAC9B;QACC+D,QAAQ;QACRC,MAAMhD,eAAe;QACrBiD,cAAc;QACdC,cAAc;kBAEd,cAAA,MAAC7D;YAAM8D,SAAS;;8BACd,MAAC5D;oBACC6D,OAAM;oBACNC,KAAK,GAAEjD,uBAAAA,QAAQc,WAAW,YAAnBd,uBAAuB;oBAC9BkD,UAAU,CAACC,QAAU/B,OAAO;4BAAEN,aAAaqC,MAAMC,MAAM,CAACH,KAAK;wBAAC;oBAC9DI,MAAK;oBACLC,MAAM;oBACNC,YACE,0DACA;;sCAGF,KAACvE;4BAASiE,OAAM;sCAAI;;wBACnB3B,cAAckC,GAAG,CAAC,CAAC,CAACC,UAAUC,KAAK,iBAClC,KAAC1E;gCAAwBiE,OAAOQ;0CAC7B,CAAC,CAAC,EAAEC,SAAS,MAAM,KAAKA,MAAM;+BADlBD;;;8BAKnB,MAACtE;oBACC6D,OAAM;oBACNC,KAAK,GAAEjD,8BAAAA,QAAQe,kBAAkB,YAA1Bf,8BAA8B;oBACrCkD,UAAU,CAACC,QACT/B,OAAO;4BAAEL,oBAAoBoC,MAAMC,MAAM,CAACH,KAAK;wBAAC;oBAElDI,MAAK;oBACLC,MAAM;oBACNC,YACE,gEACA;;sCAGF,KAACvE;4BAASiE,OAAM;sCAAI;;wBACnB3B,cAAckC,GAAG,CAAC,CAAC,CAACC,UAAUC,KAAK,iBAClC,KAAC1E;gCAAwBiE,OAAOQ;0CAC7B,CAAC,CAAC,EAAEC,SAAS,MAAM,KAAKA,MAAM;+BADlBD;;;8BAKnB,KAACtE;oBACC6D,OAAM;oBACNC,KAAK,GAAEjD,oBAAAA,QAAQgB,QAAQ,YAAhBhB,oBAAoB;oBAC3BkD,UAAU,CAACC,QAAU/B,OAAO;4BAAEJ,UAAUmC,MAAMC,MAAM,CAACH,KAAK;wBAAC;oBAC3DI,MAAK;oBACLC,MAAM;oBACNK,IAAI;wBAAEC,UAAU;oBAAI;oBACpBL,YAAW;8BAEX,cAAA,KAACvE;wBAASiE,OAAM;kCAAO;;;8BAEzB,KAAClE;oBACC8E,uBACE,KAAC3E;wBACCmE,MAAK;wBACLS,SAAS9D,QAAQiB,aAAa,KAAK;wBACnCiC,UAAU,CAACC,QACT/B,OAAO;gCAAEH,eAAekC,MAAMC,MAAM,CAACU,OAAO;4BAAC;;oBAInDd,OAAM;;8BAER,KAAC7D;oBACC6D,OAAM;oBACNC,KAAK,GAAEjD,oBAAAA,QAAQkB,QAAQ,YAAhBlB,oBAAoB;oBAC3BkD,UAAU,CAACC,QAAU/B,OAAO;4BAAEF,UAAUiC,MAAMC,MAAM,CAACH,KAAK;wBAAC;oBAC3DI,MAAK;oBACLU,aAAY;oBACZR,YAAW;;8BAEb,KAACpE;oBACC6D,OAAM;oBACNC,KAAK,GAAEjD,yBAAAA,QAAQmB,aAAa,YAArBnB,yBAAyB;oBAChCkD,UAAU,CAACC,QAAU/B,OAAO;4BAAED,eAAegC,MAAMC,MAAM,CAACH,KAAK;wBAAC;oBAChEI,MAAK;oBACLW,SAAS;oBACTC,SAAS;oBACTF,aAAY;;8BAEd,KAAC3E;oBAAWqD,SAAQ;oBAAUyB,OAAM;8BACjC,8DACC;;8BAEJ,KAACpF;oBACC2D,SAAQ;oBACRyB,OAAM;oBACNb,MAAK;oBACLc,UAAU,CAACvD;oBACXwD,SAASrC;oBACT4B,IAAI;wBAAEU,WAAW;oBAAa;8BAE7B;;;;;AAKX;AACAvE,kBAAkBwE,WAAW,GAAG;AAEhC,eAAexE,kBAAiB"}
|
|
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: '#
|
|
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
|
|
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
|
|
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(
|
|
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: `$${
|
|
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 $${
|
|
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 $${
|
|
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),
|