← 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
M lib/email.jsM lib/giftcard.jsM lib/shopify.js
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 & 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 →