← back to Dw Signup Fulfillment
feat(email): approved branded retail welcome letter + new designer welcome-on-apply letter (Steve-approved 2026-08-07); send designer welcome to applicant on /trade/apply
7f5a947261067898182d51279a59f26ebd36d54b · 2026-08-07 06:47:03 -0700 · Steve Abrams
Files touched
M lib/email.jsM server.js
Diff
commit 7f5a947261067898182d51279a59f26ebd36d54b
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Fri Aug 7 06:47:03 2026 -0700
feat(email): approved branded retail welcome letter + new designer welcome-on-apply letter (Steve-approved 2026-08-07); send designer welcome to applicant on /trade/apply
---
lib/email.js | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------
server.js | 8 +++++++
2 files changed, 68 insertions(+), 9 deletions(-)
diff --git a/lib/email.js b/lib/email.js
index cc7a91f..fa56402 100644
--- a/lib/email.js
+++ b/lib/email.js
@@ -62,16 +62,67 @@ async function sendEmail({ to, subject, html, source }) {
// ---- Templates ----
+// APPROVED retail welcome letter (Steve, 2026-08-07). Branded intro + the per-customer
+// gift code + "Explore the Collections" CTA. The gift card face value = count × sample price.
function retailGiftEmail({ firstName, code, value, count }) {
- const name = firstName ? ` ${firstName}` : '';
+ const greet = firstName ? esc(firstName) : 'there';
const subject = `Your ${count} free Designer Wallcoverings samples 🎁`;
- const html = [
- `<p>Hi${name},</p>`,
- `<p>Welcome to Designer Wallcoverings! As a thank-you for creating your account, here are your <b>${count} free samples</b>.</p>`,
- `<p style="font-size:18px;">Your gift code: <b style="letter-spacing:1px;">${esc(code)}</b> (${money(value)} value)</p>`,
- `<p>Add any ${count} sample swatches to your cart and enter this code at checkout — they're on us.</p>`,
- `<p>Happy sampling!<br><br>Designer Wallcoverings<br>${config.GEORGE_FROM}</p>`,
- ].join('\n');
+ const html = `<div style="font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;max-width:600px;margin:0 auto">
+ <div style="border:1px solid #e2ddd4;border-radius:10px;overflow:hidden">
+ <div style="background:#1a1a1a;color:#fff;text-align:center;padding:26px 20px">
+ <div style="font-size:22px;letter-spacing:3px;font-weight:600">DESIGNER WALLCOVERINGS</div>
+ <div style="font-size:11px;letter-spacing:2px;color:#b8afa2;margin-top:4px">FINE WALLCOVERINGS & FABRICS</div>
+ </div>
+ <div style="padding:26px 28px;font-size:15px;line-height:1.7;color:#2a2a2a">
+ <p style="margin:0 0 14px">Dear ${greet},</p>
+ <p style="margin:0 0 14px">Welcome to Designer Wallcoverings — your new account opens the door to the world's most beautiful wallcoverings and fabrics, from over 200 of the finest design houses, all in one place.</p>
+ <p style="margin:0 0 8px">As a thank-you for joining us, here are your <b>${count} free samples</b>. Use this code at checkout:</p>
+ <div style="text-align:center;margin:18px 0">
+ <span style="display:inline-block;background:#f4f1ea;border:1px dashed #b8afa2;border-radius:8px;padding:14px 30px;font-size:22px;letter-spacing:3px;font-weight:700;color:#1a1a1a">${esc(code)}</span>
+ </div>
+ <p style="margin:0 0 14px;color:#555;font-size:14px">Apply it to any samples in your cart — it covers ${count === 3 ? 'three' : count} at no charge (${money(value)} value). Order swatches, see them in your space, and fall in love before you commit.</p>
+ <div style="text-align:center;margin:22px 0 6px">
+ <a href="https://designerwallcoverings.com" style="background:#1a1a1a;color:#fff;text-decoration:none;padding:13px 34px;border-radius:30px;font-size:14px;letter-spacing:1px;display:inline-block">Explore the Collections</a>
+ </div>
+ <p style="margin:20px 0 0;color:#2a2a2a">Warmly,<br><b>The Designer Wallcoverings Team</b></p>
+ </div>
+ </div>
+</div>`;
+ return { subject, html };
+}
+
+// APPROVED designer/trade welcome letter (Steve, 2026-08-07). Sent to the applicant
+// immediately after they submit a trade application — "about us + services". No code
+// (designers get unlimited memo samples via the trade tag once approved).
+function designerWelcomeEmail({ firstName }) {
+ const greet = firstName ? esc(firstName) : 'there';
+ const subject = `Welcome to Designer Wallcoverings — about us & how we work with you`;
+ const html = `<div style="font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;max-width:600px;margin:0 auto">
+ <div style="border:1px solid #e2ddd4;border-radius:10px;overflow:hidden">
+ <div style="background:#1a1a1a;color:#fff;text-align:center;padding:26px 20px">
+ <div style="font-size:22px;letter-spacing:3px;font-weight:600">DESIGNER WALLCOVERINGS</div>
+ <div style="font-size:11px;letter-spacing:2px;color:#b8afa2;margin-top:4px">TO THE TRADE</div>
+ </div>
+ <div style="padding:26px 28px;font-size:15px;line-height:1.7;color:#2a2a2a">
+ <p style="margin:0 0 14px">Dear ${greet},</p>
+ <p style="margin:0 0 14px">Thank you for your interest in a Designer Wallcoverings trade account — we're delighted to welcome you.</p>
+ <p style="margin:0 0 6px"><b>Who we are.</b> Designer Wallcoverings is a to-the-trade resource representing more than 200 of the world's premier wallcovering and fabric houses — names like Schumacher, Thibaut, Cole & Son, Pierre Frey, Maya Romanoff, Élitis, Fromental and Gracie — curated in one place for designers, architects, and specifiers.</p>
+ <p style="margin:14px 0 6px"><b>How we work with you.</b></p>
+ <ul style="margin:0 0 14px;padding-left:20px;color:#333">
+ <li><b>Trade pricing</b> across every line we carry</li>
+ <li><b>Unlimited memo samples</b> — order freely for your projects</li>
+ <li><b>A dedicated account representative</b> who knows your work</li>
+ <li><b>Specification & sourcing support</b> — if it exists, we'll find it</li>
+ <li><b>Fast quoting</b> and project-level service from swatch to install</li>
+ </ul>
+ <p style="margin:0 0 14px"><b>What happens next.</b> Your trade application is being reviewed. Once approved, your account is tagged for trade pricing and your rep will reach out personally to get you started.</p>
+ <div style="text-align:center;margin:22px 0 6px">
+ <a href="https://designerwallcoverings.com" style="background:#1a1a1a;color:#fff;text-decoration:none;padding:13px 34px;border-radius:30px;font-size:14px;letter-spacing:1px;display:inline-block">Browse the Lines</a>
+ </div>
+ <p style="margin:20px 0 0;color:#2a2a2a">At your service,<br><b>The Designer Wallcoverings Trade Team</b></p>
+ </div>
+ </div>
+</div>`;
return { subject, html };
}
@@ -159,4 +210,4 @@ function tradeApplicationEmail({ app, approveUrl, rejectUrl, adminUrl }) {
function money(v) { return `$${Number(v).toFixed(2)}`; }
function esc(s) { return String(s == null ? '' : s).replace(/[&<>"]/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c])); }
-module.exports = { sendEmail, retailCodeEmail, retailGiftEmail, repNotifyEmail, tradeApprovedEmail, tradeRejectedEmail, tradeApplicationEmail, money, esc };
+module.exports = { sendEmail, retailCodeEmail, retailGiftEmail, designerWelcomeEmail, repNotifyEmail, tradeApprovedEmail, tradeRejectedEmail, tradeApplicationEmail, money, esc };
diff --git a/server.js b/server.js
index de733fa..391f7b8 100644
--- a/server.js
+++ b/server.js
@@ -122,6 +122,14 @@ app.post('/trade/apply', tradeCors, (req, res) => {
// Email the office inbox a review card with one-click Approve/Reject buttons.
// Fire-and-forget so the applicant's response isn't blocked on George; DRY_RUN-safe.
notifyTradeApplication(created).catch(e => console.error('[trade] notify failed:', e.message));
+ // Also send the applicant the "about us + services" welcome letter (approved 2026-08-07).
+ // Fire-and-forget + DRY_RUN-safe; a George hiccup must not fail the applicant's submit.
+ (async () => {
+ const first = created.first_name || (created.contact_name ? String(created.contact_name).split(' ')[0] : '') || (created.email ? created.email.split('@')[0] : '');
+ const { subject, html } = email.designerWelcomeEmail({ firstName: first });
+ const r = await email.sendEmail({ to: created.email, subject, html, source: 'designer-welcome' });
+ if (r && r.ok === false) console.error(`[trade] designer-welcome send FAILED for ${created.email}: ${r.error || r.status}`);
+ })().catch(e => console.error('[trade] designer-welcome error:', e.message));
res.json({ ok: true, id: created.id, status: created.status, created_at: created.created_at });
});
← 848697f fix(theme): point trade-apply modal at canonical signup.desi
·
back to Dw Signup Fulfillment
·
trade-invite outreach: time-boxed office-copy hook + send sc bb988c6 →