@aglyn/plugins-commerce 1.0.0-beta.291 → 1.0.0-beta.293
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/README.md +1 -0
- package/package.json +13 -13
- package/src/lib/components/cart-fulfillment.d.ts +3 -0
- package/src/lib/components/cart-fulfillment.js.map +1 -1
- package/src/lib/components/cart.js +14 -4
- package/src/lib/components/cart.js.map +1 -1
- package/src/lib/components/console/host-quotes-card.component.js +11 -9
- package/src/lib/components/console/host-quotes-card.component.js.map +1 -1
- package/src/lib/components/console/invoice-send.component.js +1 -1
- package/src/lib/components/console/invoice-send.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-item-dialog.component.js +3 -2
- package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -1
- package/src/lib/components/console/pos-kiosk-page.component.js +2 -1
- package/src/lib/components/console/pos-kiosk-page.component.js.map +1 -1
- package/src/lib/components/console/pos-page.component.js +1 -1
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/product-add-ons-fields.component.d.ts +41 -0
- package/src/lib/components/console/product-add-ons-fields.component.js +356 -0
- package/src/lib/components/console/product-add-ons-fields.component.js.map +1 -0
- package/src/lib/components/console/product-editor-dialog.component.js +31 -5
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/product-register-fields.component.d.ts +4 -5
- package/src/lib/components/console/product-register-fields.component.js +8 -197
- package/src/lib/components/console/product-register-fields.component.js.map +1 -1
- package/src/lib/components/console/products-hub-zone.component.js +6 -0
- package/src/lib/components/console/products-hub-zone.component.js.map +1 -1
- package/src/lib/components/console/quote-pay-link.component.d.ts +8 -1
- package/src/lib/components/console/quote-pay-link.component.js +29 -3
- package/src/lib/components/console/quote-pay-link.component.js.map +1 -1
- package/src/lib/components/console/quote-send.component.js +1 -4
- package/src/lib/components/console/quote-send.component.js.map +1 -1
- package/src/lib/components/product-add-ons.d.ts +28 -0
- package/src/lib/components/product-add-ons.js +136 -0
- package/src/lib/components/product-add-ons.js.map +1 -0
- package/src/lib/components/product-detail.d.ts +16 -0
- package/src/lib/components/product-detail.js +112 -19
- package/src/lib/components/product-detail.js.map +1 -1
- package/src/lib/components/product-grid.d.ts +8 -2
- package/src/lib/components/product-grid.js +6 -1
- package/src/lib/components/product-grid.js.map +1 -1
- package/src/lib/declarations.console-server.js +15 -0
- package/src/lib/declarations.console-server.js.map +1 -1
- package/src/lib/model/commerce-cart.d.ts +15 -3
- package/src/lib/model/commerce-cart.js +10 -3
- package/src/lib/model/commerce-cart.js.map +1 -1
- package/src/lib/model/commerce-invoices.d.ts +7 -0
- package/src/lib/model/commerce-invoices.js +11 -0
- package/src/lib/model/commerce-invoices.js.map +1 -1
- package/src/lib/model/commerce-orders.d.ts +6 -3
- package/src/lib/model/commerce-orders.js +3 -0
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce-pos-kiosk.d.ts +1 -1
- package/src/lib/model/commerce-pos-kiosk.js +3 -2
- package/src/lib/model/commerce-pos-kiosk.js.map +1 -1
- package/src/lib/model/commerce-quote-email.d.ts +14 -0
- package/src/lib/model/commerce-quote-email.js +25 -9
- package/src/lib/model/commerce-quote-email.js.map +1 -1
- package/src/lib/model/commerce-quote-proofs.d.ts +7 -0
- package/src/lib/model/commerce-quote-proofs.js +15 -0
- package/src/lib/model/commerce-quote-proofs.js.map +1 -1
- package/src/lib/model/commerce-quotes.js +1 -1
- package/src/lib/model/commerce-quotes.js.map +1 -1
- package/src/lib/model/commerce.d.ts +18 -0
- package/src/lib/model/commerce.js +26 -0
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/product-modifiers.d.ts +74 -4
- package/src/lib/model/product-modifiers.js +131 -10
- package/src/lib/model/product-modifiers.js.map +1 -1
- package/src/lib/server/billing-webhook.js +64 -43
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cart-checkout.js +14 -2
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/cart.d.ts +5 -0
- package/src/lib/server/cart.js +41 -4
- package/src/lib/server/cart.js.map +1 -1
- package/src/lib/server/catalog.d.ts +6 -0
- package/src/lib/server/catalog.js +2 -0
- package/src/lib/server/catalog.js.map +1 -1
- package/src/lib/server/checkout-extras.js +3 -1
- package/src/lib/server/checkout-extras.js.map +1 -1
- package/src/lib/server/checkout.js +28 -3
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/local-fulfillment.js +5 -1
- package/src/lib/server/local-fulfillment.js.map +1 -1
- package/src/lib/server/pos-offline-sync.js +1 -1
- package/src/lib/server/pos-offline-sync.js.map +1 -1
- package/src/lib/server/pos-order.js +1 -1
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/product.d.ts +26 -0
- package/src/lib/server/product.js +18 -0
- package/src/lib/server/product.js.map +1 -1
- package/src/lib/server/products-write.js +5 -2
- package/src/lib/server/products-write.js.map +1 -1
- package/src/lib/server/quote-email.js.map +1 -1
- package/src/lib/server/quote-link-token.d.ts +4 -2
- package/src/lib/server/quote-link-token.js +4 -2
- package/src/lib/server/quote-link-token.js.map +1 -1
- package/src/lib/server/quote-pay.d.ts +5 -1
- package/src/lib/server/quote-pay.js +5 -2
- package/src/lib/server/quote-pay.js.map +1 -1
- package/src/lib/server/quote-proofs.d.ts +9 -1
- package/src/lib/server/quote-proofs.js +92 -23
- package/src/lib/server/quote-proofs.js.map +1 -1
- package/src/lib/server/quote-upload-keys.d.ts +50 -0
- package/src/lib/server/quote-upload-keys.js +86 -0
- package/src/lib/server/quote-upload-keys.js.map +1 -0
- package/src/lib/server/quote-upload-sweep.d.ts +30 -0
- package/src/lib/server/quote-upload-sweep.js +117 -0
- package/src/lib/server/quote-upload-sweep.js.map +1 -0
- package/src/lib/utils/add-to-cart.d.ts +8 -0
- package/src/lib/utils/add-to-cart.js +10 -2
- package/src/lib/utils/add-to-cart.js.map +1 -1
- package/src/lib/utils/quote-email-content.d.ts +1 -0
- package/src/lib/utils/quote-email-content.js +7 -4
- package/src/lib/utils/quote-email-content.js.map +1 -1
|
@@ -13,13 +13,15 @@
|
|
|
13
13
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
|
-
*/ import { currentQuoteProofs, formatOrderMoney, formatQuoteNumber, quotePaymentBlockedByApproval } from "../model/index.js";
|
|
16
|
+
*/ import { currentQuoteProofs, formatOrderMoney, formatQuoteNumber, quotePaymentBlockedByApproval, quoteSendIsNewRevision } from "../model/index.js";
|
|
17
17
|
import { escapeHtml } from "./escape-html.js";
|
|
18
18
|
/*==========================================
|
|
19
19
|
* WHAT THE QUOTE EMAIL SAYS (AGL-4097).
|
|
20
20
|
*
|
|
21
21
|
* The `quote-sent` catalog email's tokens, composed per send: its heading,
|
|
22
|
-
* what this email is (a
|
|
22
|
+
* what this email is (a quote, or an updated revision of one the customer was
|
|
23
|
+
* already emailed: `quoteSendIsNewRevision`, read off the sends on record
|
|
24
|
+
* before this one, so a first email or a resend never says "updated"), the business's
|
|
23
25
|
* own message, the quote's number, revision and total, up to three proof
|
|
24
26
|
* images, the other proof files by name, what to do next and the button. The
|
|
25
27
|
* next step and the button follow the business's approval control
|
|
@@ -93,8 +95,9 @@ const plural = (count, one, many)=>`${count} ${count === 1 ? one : many}`;
|
|
|
93
95
|
const proofFiles = parts.length ? `${lead}: ${joinNames(parts)}. ${seeIt}` : '';
|
|
94
96
|
const radius = Math.max(0, Math.round(Number((_input_radius = input.radius) != null ? _input_radius : 4)) || 0);
|
|
95
97
|
const proofImages = proofImagesHtml(pictured, input.payUrl, input.colors, radius);
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
+
const updated = quoteSendIsNewRevision(quote);
|
|
99
|
+
const heading = updated ? 'Your updated quote' : businessName.trim() ? `Your quote from ${businessName.trim()}` : 'Your quote';
|
|
100
|
+
const intro = updated ? `${capitalize(business)} updated your quote. This is revision ${revision}, and it replaces the one sent before.` + (input.linkReplaced ? ' The link in the earlier email no longer opens the quote, so use the button below.' : '') + ' The new version is attached as a PDF.' : `${capitalize(business)} put together a quote for you. The details are below, and the quote is attached as a PDF.`;
|
|
98
101
|
const proofed = proofs.length > 0;
|
|
99
102
|
const approved = proofed && Number(quote.approvedRevision) === revision;
|
|
100
103
|
const nextStep = approvalFirst ? 'Look over the proof, then approve it on your quote page. Once you approve it, you can pay there.' : approved ? 'You approved the proof. Pay on your quote page whenever you’re ready.' : proofed ? 'Look over your quote and the proof. On your quote page you can approve the proof or ask for changes, and pay whenever you’re ready.' : 'Look over your quote, and pay it on your quote page whenever you’re ready.';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/utils/quote-email-content.ts"],"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 {\n currentQuoteProofs,\n formatOrderMoney,\n formatQuoteNumber,\n quotePaymentBlockedByApproval,\n type HostOrder,\n type OrderQuote,\n} from '../model'\nimport { escapeHtml } from './escape-html'\n\n/*==========================================\n * WHAT THE QUOTE EMAIL SAYS (AGL-4097).\n *\n * The `quote-sent` catalog email's tokens, composed per send: its heading,\n * what this email is (a new quote, or an updated revision), the business's\n * own message, the quote's number, revision and total, up to three proof\n * images, the other proof files by name, what to do next and the button. The\n * next step and the button follow the business's approval control\n * (`quotePaymentBlockedByApproval`): while the customer must approve the\n * proof first, the button is \"Review and approve\"; otherwise it is \"View and\n * pay\" with the total. Both go to the quote's pay link, where the customer\n * does either.\n *\n * Prices appear only in the tokens the catalog names for them\n * (`quote.total`, `quote.buttonLabel`); the composed markup\n * (`quote.proofImages`) carries pictures and file names, nothing else.\n *\n * Pure: the send route and the sample renders call the same function.\n *=========================================*/\n\n/** The catalog key the quote email is sent and designed under. */\nexport const QUOTE_EMAIL_KEY = 'quote-sent'\n\n/** The most proof images drawn in the email; the rest are named. */\nexport const QUOTE_EMAIL_MAX_IMAGES = 3\n\n/**\n * The column's inner width in the built-in copy: the 600px column less the\n * section's padding on each side.\n */\nexport const QUOTE_EMAIL_IMAGE_WIDTH = 552\n\n/**\n * Pictures every inbox draws. WebP is left to the quote page, where it shows:\n * Outlook for Windows draws no WebP.\n */\nconst EMAIL_IMAGE_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif'])\n\n/** The most file names listed before \"and N more\". */\nconst MAX_NAMED_FILES = 5\n\n/** The theme's colors the composed markup draws with, resolved by the sender. */\nexport interface QuoteEmailColors {\n /** The images' outline: the theme's divider. */\n border: string\n /** The caption under each image: the theme's secondary text. */\n muted: string\n}\n\nexport interface QuoteEmailContentInput {\n order: HostOrder\n quoteId: string\n businessName: string\n currency: string\n /** The subject the email goes under. */\n subject: string\n /** The business's message, as typed; may be empty. */\n message: string\n /** The quote's pay link, at the version this email carries. */\n payUrl: string\n /** A proof's address behind that link, or null when it has none. */\n proofUrl: (proofId: string) => string | null\n /** This email gives the customer a new pay link, and the earlier email's no longer opens the quote. */\n linkReplaced: boolean\n colors: QuoteEmailColors\n /** The theme's corner radius in px, for the images. */\n radius?: number\n}\n\nexport interface QuoteEmailContent {\n /** The catalog email's merge tokens. */\n tokens: Record<string, string>\n /** The same email as plain text, for a send whose design cannot be rendered. */\n text: string\n /** The customer approves the proof before they can pay: the button reads \"Review and approve\". */\n approvalFirst: boolean\n}\n\n/** `a`, `a and b`, `a, b and c`. */\nfunction joinNames(names: readonly string[]): string {\n if (names.length <= 1) return names.join('')\n return `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`\n}\n\nconst plural = (count: number, one: string, many: string) => `${count} ${count === 1 ? one : many}`\n\n/** The quote email's tokens and its plain-text twin. */\nexport function quoteEmailContent(input: QuoteEmailContentInput): QuoteEmailContent {\n const { order, businessName } = input\n const quote = (order.quote ?? {}) as OrderQuote\n const business = businessName.trim() || 'the business'\n const revision = Math.max(1, Math.floor(Number(quote.revision ?? 1)) || 1)\n const number = formatQuoteNumber(order, input.quoteId).replace(/^Quote\\s+/, '')\n const taxAtPayment = quote.tax?.kind === 'at-payment'\n const money = formatOrderMoney(Number(order.totals?.totalCents ?? 0), input.currency)\n const total = taxAtPayment ? `${money} before tax` : money\n const approvalFirst = quotePaymentBlockedByApproval(quote)\n\n // The proofs: pictures an inbox draws, up to three, then every other file by name.\n const proofs = currentQuoteProofs(quote)\n const pictured: Array<{ name: string; url: string }> = []\n const named: string[] = []\n let morePictures = 0\n for (const proof of proofs) {\n const url = EMAIL_IMAGE_TYPES.has(String(proof.contentType ?? '').toLowerCase()) ? input.proofUrl(proof.id) : null\n if (url && pictured.length < QUOTE_EMAIL_MAX_IMAGES) pictured.push({ name: proof.name, url })\n else if (url) morePictures += 1\n else named.push(proof.name)\n }\n const listed = named.slice(0, MAX_NAMED_FILES)\n const overflow = named.length - listed.length + morePictures\n const parts = [...listed, ...(overflow > 0 ? [`${plural(overflow, 'more file', 'more files')}`] : [])]\n const lead = pictured.length ? 'Also with this revision' : named.length === 1 ? 'Proof' : 'Proofs'\n const seeIt = named.length + morePictures === 1 ? 'See it on your quote page.' : 'See them on your quote page.'\n const proofFiles = parts.length ? `${lead}: ${joinNames(parts)}. ${seeIt}` : ''\n\n const radius = Math.max(0, Math.round(Number(input.radius ?? 4)) || 0)\n const proofImages = proofImagesHtml(pictured, input.payUrl, input.colors, radius)\n\n const heading = revision >= 2 ? 'Your updated quote' : businessName.trim() ? `Your quote from ${businessName.trim()}` : 'Your quote'\n const intro =\n revision >= 2\n ? `${capitalize(business)} updated your quote. This is revision ${revision}, and it replaces the one sent before.` +\n (input.linkReplaced ? ' The link in the earlier email no longer opens the quote, so use the button below.' : '') +\n ' The new version is attached as a PDF.'\n : `${capitalize(business)} put together a quote for you. The details are below, and the quote is attached as a PDF.`\n\n const proofed = proofs.length > 0\n const approved = proofed && Number(quote.approvedRevision) === revision\n const nextStep = approvalFirst\n ? 'Look over the proof, then approve it on your quote page. Once you approve it, you can pay there.'\n : approved\n ? 'You approved the proof. Pay on your quote page whenever you’re ready.'\n : proofed\n ? 'Look over your quote and the proof. On your quote page you can approve the proof or ask for changes, and pay whenever you’re ready.'\n : 'Look over your quote, and pay it on your quote page whenever you’re ready.'\n const buttonLabel = approvalFirst ? 'Review and approve' : `View and pay ${money}${taxAtPayment ? ' plus tax' : ''}`\n const message = input.message.trim()\n\n const tokens: Record<string, string> = {\n 'quote.subject': input.subject,\n 'quote.number': number,\n 'quote.revision': String(revision),\n 'quote.total': total,\n 'quote.heading': heading,\n 'quote.intro': intro,\n 'quote.message': message,\n 'quote.proofImages': proofImages,\n 'quote.proofFiles': proofFiles,\n 'quote.nextStep': nextStep,\n 'quote.buttonLabel': buttonLabel,\n 'quote.url': input.payUrl,\n }\n\n const text = [\n heading,\n intro,\n message,\n `Quote: ${number}\\nRevision: ${revision}\\nTotal: ${total}`,\n pictured.length ? `Proof: ${joinNames(pictured.map((proof) => proof.name))}` : '',\n proofFiles,\n nextStep,\n `${buttonLabel}: ${input.payUrl}`,\n `Reply to this email to reach ${business}.`,\n ]\n .filter(Boolean)\n .join('\\n\\n')\n\n return { tokens, text, approvalFirst }\n}\n\n/** The space between two pictures side by side, in px. */\nconst IMAGE_GAP = 12\n\n/**\n * The proof pictures, each linked to the quote page with its file name under\n * it: one across the column, or two or three side by side, so the button\n * stays near. A table, the layout every inbox keeps.\n */\nfunction proofImagesHtml(\n pictured: ReadonlyArray<{ name: string; url: string }>,\n payUrl: string,\n colors: QuoteEmailColors,\n radius: number,\n): string {\n if (!pictured.length) return ''\n const count = pictured.length\n const width = Math.floor((QUOTE_EMAIL_IMAGE_WIDTH - IMAGE_GAP * (count - 1)) / count)\n const cells = pictured.map((proof, index) => {\n const left = index === 0 ? 0 : IMAGE_GAP / 2\n const right = index === count - 1 ? 0 : IMAGE_GAP / 2\n return (\n `<td style=\"width:${Math.round(100 / count)}%;vertical-align:top;padding:4px ${right}px 12px ${left}px;\">` +\n `<a href=\"${escapeHtml(payUrl)}\">` +\n `<img src=\"${escapeHtml(proof.url)}\" alt=\"${escapeHtml(`Proof: ${proof.name}`)}\" width=\"${width}\" ` +\n `style=\"display:block;width:100%;max-width:${width}px;height:auto;box-sizing:border-box;` +\n `border:1px solid ${colors.border};border-radius:${radius}px;\" />` +\n `</a>` +\n `<div style=\"font-size:13px;line-height:1.4;color:${colors.muted};padding-top:6px;word-break:break-word;\">${escapeHtml(proof.name)}</div>` +\n `</td>`\n )\n })\n return (\n `<table role=\"presentation\" style=\"width:100%;border-collapse:collapse;\">` +\n `<tr>${cells.join('')}</tr>` +\n `</table>`\n )\n}\n\nfunction capitalize(value: string): string {\n return value ? value[0].toUpperCase() + value.slice(1) : value\n}\n"],"names":["currentQuoteProofs","formatOrderMoney","formatQuoteNumber","quotePaymentBlockedByApproval","escapeHtml","QUOTE_EMAIL_KEY","QUOTE_EMAIL_MAX_IMAGES","QUOTE_EMAIL_IMAGE_WIDTH","EMAIL_IMAGE_TYPES","Set","MAX_NAMED_FILES","joinNames","names","length","join","slice","plural","count","one","many","quoteEmailContent","input","order","quote","businessName","business","trim","revision","Math","max","floor","Number","number","quoteId","replace","taxAtPayment","tax","kind","money","totals","totalCents","currency","total","approvalFirst","proofs","pictured","named","morePictures","proof","url","has","String","contentType","toLowerCase","proofUrl","id","push","name","listed","overflow","parts","lead","seeIt","proofFiles","radius","round","proofImages","proofImagesHtml","payUrl","colors","heading","intro","capitalize","linkReplaced","proofed","approved","approvedRevision","nextStep","buttonLabel","message","tokens","subject","text","map","filter","Boolean","IMAGE_GAP","width","cells","index","left","right","border","muted","value","toUpperCase"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/utils/quote-email-content.ts"],"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 {\n currentQuoteProofs,\n formatOrderMoney,\n formatQuoteNumber,\n quotePaymentBlockedByApproval,\n quoteSendIsNewRevision,\n type HostOrder,\n type OrderQuote,\n} from '../model'\nimport { escapeHtml } from './escape-html'\n\n/*==========================================\n * WHAT THE QUOTE EMAIL SAYS (AGL-4097).\n *\n * The `quote-sent` catalog email's tokens, composed per send: its heading,\n * what this email is (a quote, or an updated revision of one the customer was\n * already emailed: `quoteSendIsNewRevision`, read off the sends on record\n * before this one, so a first email or a resend never says \"updated\"), the business's\n * own message, the quote's number, revision and total, up to three proof\n * images, the other proof files by name, what to do next and the button. The\n * next step and the button follow the business's approval control\n * (`quotePaymentBlockedByApproval`): while the customer must approve the\n * proof first, the button is \"Review and approve\"; otherwise it is \"View and\n * pay\" with the total. Both go to the quote's pay link, where the customer\n * does either.\n *\n * Prices appear only in the tokens the catalog names for them\n * (`quote.total`, `quote.buttonLabel`); the composed markup\n * (`quote.proofImages`) carries pictures and file names, nothing else.\n *\n * Pure: the send route and the sample renders call the same function.\n *=========================================*/\n\n/** The catalog key the quote email is sent and designed under. */\nexport const QUOTE_EMAIL_KEY = 'quote-sent'\n\n/** The most proof images drawn in the email; the rest are named. */\nexport const QUOTE_EMAIL_MAX_IMAGES = 3\n\n/**\n * The column's inner width in the built-in copy: the 600px column less the\n * section's padding on each side.\n */\nexport const QUOTE_EMAIL_IMAGE_WIDTH = 552\n\n/**\n * Pictures every inbox draws. WebP is left to the quote page, where it shows:\n * Outlook for Windows draws no WebP.\n */\nconst EMAIL_IMAGE_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif'])\n\n/** The most file names listed before \"and N more\". */\nconst MAX_NAMED_FILES = 5\n\n/** The theme's colors the composed markup draws with, resolved by the sender. */\nexport interface QuoteEmailColors {\n /** The images' outline: the theme's divider. */\n border: string\n /** The caption under each image: the theme's secondary text. */\n muted: string\n}\n\nexport interface QuoteEmailContentInput {\n /** The quote as this email finds it: its `quote.sends` are the emails before this one. */\n order: HostOrder\n quoteId: string\n businessName: string\n currency: string\n /** The subject the email goes under. */\n subject: string\n /** The business's message, as typed; may be empty. */\n message: string\n /** The quote's pay link, at the version this email carries. */\n payUrl: string\n /** A proof's address behind that link, or null when it has none. */\n proofUrl: (proofId: string) => string | null\n /** This email gives the customer a new pay link, and the earlier email's no longer opens the quote. */\n linkReplaced: boolean\n colors: QuoteEmailColors\n /** The theme's corner radius in px, for the images. */\n radius?: number\n}\n\nexport interface QuoteEmailContent {\n /** The catalog email's merge tokens. */\n tokens: Record<string, string>\n /** The same email as plain text, for a send whose design cannot be rendered. */\n text: string\n /** The customer approves the proof before they can pay: the button reads \"Review and approve\". */\n approvalFirst: boolean\n}\n\n/** `a`, `a and b`, `a, b and c`. */\nfunction joinNames(names: readonly string[]): string {\n if (names.length <= 1) return names.join('')\n return `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`\n}\n\nconst plural = (count: number, one: string, many: string) => `${count} ${count === 1 ? one : many}`\n\n/** The quote email's tokens and its plain-text twin. */\nexport function quoteEmailContent(input: QuoteEmailContentInput): QuoteEmailContent {\n const { order, businessName } = input\n const quote = (order.quote ?? {}) as OrderQuote\n const business = businessName.trim() || 'the business'\n const revision = Math.max(1, Math.floor(Number(quote.revision ?? 1)) || 1)\n const number = formatQuoteNumber(order, input.quoteId).replace(/^Quote\\s+/, '')\n const taxAtPayment = quote.tax?.kind === 'at-payment'\n const money = formatOrderMoney(Number(order.totals?.totalCents ?? 0), input.currency)\n const total = taxAtPayment ? `${money} before tax` : money\n const approvalFirst = quotePaymentBlockedByApproval(quote)\n\n // The proofs: pictures an inbox draws, up to three, then every other file by name.\n const proofs = currentQuoteProofs(quote)\n const pictured: Array<{ name: string; url: string }> = []\n const named: string[] = []\n let morePictures = 0\n for (const proof of proofs) {\n const url = EMAIL_IMAGE_TYPES.has(String(proof.contentType ?? '').toLowerCase()) ? input.proofUrl(proof.id) : null\n if (url && pictured.length < QUOTE_EMAIL_MAX_IMAGES) pictured.push({ name: proof.name, url })\n else if (url) morePictures += 1\n else named.push(proof.name)\n }\n const listed = named.slice(0, MAX_NAMED_FILES)\n const overflow = named.length - listed.length + morePictures\n const parts = [...listed, ...(overflow > 0 ? [`${plural(overflow, 'more file', 'more files')}`] : [])]\n const lead = pictured.length ? 'Also with this revision' : named.length === 1 ? 'Proof' : 'Proofs'\n const seeIt = named.length + morePictures === 1 ? 'See it on your quote page.' : 'See them on your quote page.'\n const proofFiles = parts.length ? `${lead}: ${joinNames(parts)}. ${seeIt}` : ''\n\n const radius = Math.max(0, Math.round(Number(input.radius ?? 4)) || 0)\n const proofImages = proofImagesHtml(pictured, input.payUrl, input.colors, radius)\n\n const updated = quoteSendIsNewRevision(quote)\n const heading = updated ? 'Your updated quote' : businessName.trim() ? `Your quote from ${businessName.trim()}` : 'Your quote'\n const intro = updated\n ? `${capitalize(business)} updated your quote. This is revision ${revision}, and it replaces the one sent before.` +\n (input.linkReplaced ? ' The link in the earlier email no longer opens the quote, so use the button below.' : '') +\n ' The new version is attached as a PDF.'\n : `${capitalize(business)} put together a quote for you. The details are below, and the quote is attached as a PDF.`\n\n const proofed = proofs.length > 0\n const approved = proofed && Number(quote.approvedRevision) === revision\n const nextStep = approvalFirst\n ? 'Look over the proof, then approve it on your quote page. Once you approve it, you can pay there.'\n : approved\n ? 'You approved the proof. Pay on your quote page whenever you’re ready.'\n : proofed\n ? 'Look over your quote and the proof. On your quote page you can approve the proof or ask for changes, and pay whenever you’re ready.'\n : 'Look over your quote, and pay it on your quote page whenever you’re ready.'\n const buttonLabel = approvalFirst ? 'Review and approve' : `View and pay ${money}${taxAtPayment ? ' plus tax' : ''}`\n const message = input.message.trim()\n\n const tokens: Record<string, string> = {\n 'quote.subject': input.subject,\n 'quote.number': number,\n 'quote.revision': String(revision),\n 'quote.total': total,\n 'quote.heading': heading,\n 'quote.intro': intro,\n 'quote.message': message,\n 'quote.proofImages': proofImages,\n 'quote.proofFiles': proofFiles,\n 'quote.nextStep': nextStep,\n 'quote.buttonLabel': buttonLabel,\n 'quote.url': input.payUrl,\n }\n\n const text = [\n heading,\n intro,\n message,\n `Quote: ${number}\\nRevision: ${revision}\\nTotal: ${total}`,\n pictured.length ? `Proof: ${joinNames(pictured.map((proof) => proof.name))}` : '',\n proofFiles,\n nextStep,\n `${buttonLabel}: ${input.payUrl}`,\n `Reply to this email to reach ${business}.`,\n ]\n .filter(Boolean)\n .join('\\n\\n')\n\n return { tokens, text, approvalFirst }\n}\n\n/** The space between two pictures side by side, in px. */\nconst IMAGE_GAP = 12\n\n/**\n * The proof pictures, each linked to the quote page with its file name under\n * it: one across the column, or two or three side by side, so the button\n * stays near. A table, the layout every inbox keeps.\n */\nfunction proofImagesHtml(\n pictured: ReadonlyArray<{ name: string; url: string }>,\n payUrl: string,\n colors: QuoteEmailColors,\n radius: number,\n): string {\n if (!pictured.length) return ''\n const count = pictured.length\n const width = Math.floor((QUOTE_EMAIL_IMAGE_WIDTH - IMAGE_GAP * (count - 1)) / count)\n const cells = pictured.map((proof, index) => {\n const left = index === 0 ? 0 : IMAGE_GAP / 2\n const right = index === count - 1 ? 0 : IMAGE_GAP / 2\n return (\n `<td style=\"width:${Math.round(100 / count)}%;vertical-align:top;padding:4px ${right}px 12px ${left}px;\">` +\n `<a href=\"${escapeHtml(payUrl)}\">` +\n `<img src=\"${escapeHtml(proof.url)}\" alt=\"${escapeHtml(`Proof: ${proof.name}`)}\" width=\"${width}\" ` +\n `style=\"display:block;width:100%;max-width:${width}px;height:auto;box-sizing:border-box;` +\n `border:1px solid ${colors.border};border-radius:${radius}px;\" />` +\n `</a>` +\n `<div style=\"font-size:13px;line-height:1.4;color:${colors.muted};padding-top:6px;word-break:break-word;\">${escapeHtml(proof.name)}</div>` +\n `</td>`\n )\n })\n return (\n `<table role=\"presentation\" style=\"width:100%;border-collapse:collapse;\">` +\n `<tr>${cells.join('')}</tr>` +\n `</table>`\n )\n}\n\nfunction capitalize(value: string): string {\n return value ? value[0].toUpperCase() + value.slice(1) : value\n}\n"],"names":["currentQuoteProofs","formatOrderMoney","formatQuoteNumber","quotePaymentBlockedByApproval","quoteSendIsNewRevision","escapeHtml","QUOTE_EMAIL_KEY","QUOTE_EMAIL_MAX_IMAGES","QUOTE_EMAIL_IMAGE_WIDTH","EMAIL_IMAGE_TYPES","Set","MAX_NAMED_FILES","joinNames","names","length","join","slice","plural","count","one","many","quoteEmailContent","input","order","quote","businessName","business","trim","revision","Math","max","floor","Number","number","quoteId","replace","taxAtPayment","tax","kind","money","totals","totalCents","currency","total","approvalFirst","proofs","pictured","named","morePictures","proof","url","has","String","contentType","toLowerCase","proofUrl","id","push","name","listed","overflow","parts","lead","seeIt","proofFiles","radius","round","proofImages","proofImagesHtml","payUrl","colors","updated","heading","intro","capitalize","linkReplaced","proofed","approved","approvedRevision","nextStep","buttonLabel","message","tokens","subject","text","map","filter","Boolean","IMAGE_GAP","width","cells","index","left","right","border","muted","value","toUpperCase"],"mappings":"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"}
|