[object Object]

← back to Dw Signup Fulfillment

signups: designer welcome auto-sends create-account CTA; retail gift code now short DW###### (8-char)

f4883162f3a9e14bc92c6bd8b140d5f1a543831b · 2026-08-07 07:53:20 -0700 · Steve Abrams

Files touched

Diff

commit f4883162f3a9e14bc92c6bd8b140d5f1a543831b
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Aug 7 07:53:20 2026 -0700

    signups: designer welcome auto-sends create-account CTA; retail gift code now short DW###### (8-char)
---
 lib/email.js    |  7 ++++---
 lib/giftcard.js | 13 ++++++++++++-
 lib/shopify.js  | 10 ++++++----
 3 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/lib/email.js b/lib/email.js
index 5c94c7f..1ff9ace 100644
--- a/lib/email.js
+++ b/lib/email.js
@@ -119,7 +119,8 @@ function retailGiftEmail({ firstName, code, value, count }) {
 // 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 fn = firstName ? String(firstName).trim() : '';
+  const greet = fn ? esc(fn.charAt(0).toUpperCase() + fn.slice(1)) : '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">
@@ -139,9 +140,9 @@ function designerWelcomeEmail({ firstName }) {
         <li><b>Specification &amp; 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>
+      <p style="margin:0 0 14px"><b>What happens next.</b> One quick step activates everything: <b>create or sign in to your free Designer Wallcoverings account</b> (about a minute). Once you have an account we switch on your trade pricing and unlimited memo samples, and your dedicated 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>
+        <a href="https://designerwallcoverings.com/account" style="background:#1a1a1a;color:#fff;text-decoration:none;padding:13px 34px;border-radius:30px;font-size:14px;letter-spacing:1px;display:inline-block">Create / Sign In to Your Account</a>
       </div>
       <p style="margin:20px 0 0;color:#2a2a2a">At your service,<br><b>The Designer Wallcoverings Trade Team</b></p>
     </div>
diff --git a/lib/giftcard.js b/lib/giftcard.js
index 368415e..850ea50 100644
--- a/lib/giftcard.js
+++ b/lib/giftcard.js
@@ -20,15 +20,26 @@
 //
 // DRY_RUN-safe: lib/shopify.js short-circuits the POST and returns a synthetic
 // gift_card with a DRYRUN… code so the email template still has something to show.
+const crypto = require('crypto');
 const config = require('./config');
 const shopify = require('./shopify');
 const email = require('./email');
 
+// Short, human-friendly gift-card code: DW + 6 chars from an unambiguous alphabet
+// (no 0/O/1/I/L) = 8 chars total, Shopify's minimum. ~32^6 ≈ 1B combos → negligible
+// collision at DW volume. Replaces Shopify's long auto-generated code.
+function shortGiftCode() {
+  const ALPHABET = 'ABCDEFGHJKMNPQRSTUVWXYZ23456789'; // 30 chars, no look-alikes
+  let s = '';
+  for (let i = 0; i < 6; i++) s += ALPHABET[crypto.randomInt(ALPHABET.length)];
+  return 'DW' + s;
+}
+
 async function issueRetailGiftCode(customer) {
   const value = config.SAMPLE_GIFT_VALUE; // 3 × 4.25
   const note = `DW retail free samples (${config.FREE_SAMPLE_COUNT} × $${config.SAMPLE_PRICE}) — customer ${customer.email || customer.id}`;
 
-  const gc = await shopify.createGiftCard({ value, note, currency: config.CURRENCY });
+  const gc = await shopify.createGiftCard({ value, note, currency: config.CURRENCY, code: shortGiftCode() });
   const card = gc.json && gc.json.gift_card ? gc.json.gift_card : {};
   const code = card.code || '(code returned by Shopify at go-live)';
 
diff --git a/lib/shopify.js b/lib/shopify.js
index 1fa9ce2..70e9ee4 100644
--- a/lib/shopify.js
+++ b/lib/shopify.js
@@ -75,10 +75,12 @@ function synthetic(path, body) {
 // ---- High-level helpers ----
 
 // Create a Shopify gift card with a fixed initial_value.
-async function createGiftCard({ value, note, currency }) {
-  return request('POST', '/gift_cards.json', {
-    gift_card: { initial_value: String(value), note: note || 'DW retail free-samples', currency: currency || config.CURRENCY },
-  });
+async function createGiftCard({ value, note, currency, code }) {
+  const gift_card = { initial_value: String(value), note: note || 'DW retail free-samples', currency: currency || config.CURRENCY };
+  // Shopify auto-generates a long random code unless we supply our own. A custom code
+  // must be >= 8 chars; we pass a short branded DW###### so the email is easy to read/type.
+  if (code) gift_card.code = code;
+  return request('POST', '/gift_cards.json', { gift_card });
 }
 
 // Add tags to a customer (tagsAdd equivalent — REST needs the merged tag string,

← bb988c6 trade-invite outreach: time-boxed office-copy hook + send sc  ·  back to Dw Signup Fulfillment  ·  retail gift code: uppercase for display in email (DWSR2VEF), f7846f6 →