← back to Lawyer Directory Builder
Iter 37: /data/thanks editorial confirmation matching iter 25 pattern
f10bb428acf303b48b4e38b91418b6aef90be376 · 2026-05-04 07:07:24 -0700 · SteveStudio2
Brought /data/thanks paid path to the editorial standard set by
/upgrade/thanks (iter 25). Was eyebrow + h1 + button + bookmark URL —
minimal next to the polished /upgrade/thanks for the same money.
What shipped on the paid path:
- Volume strip 'Edition 2026 · Order Confirmed' (or 'Subscription
Active' for the recurring tier)
- Italic-metal display 'Your data is ready.' (kept; still right)
- Order № receipt strip — DATA-YYYY-MMDD-NNNN format, italic-metal
tabular-nums (matches EZ-YYYY-MMDD-NNNN on /upgrade/thanks). Three
cols: Order №, Logged, Charged ($amount). For subscription tier
shows '$X/mo' and label 'Recurring'.
- 'What's next' 3-cell grid:
i. Download the CSV — flat-noir + champagne-hairline button
ii. Bookmark your download URL — full URL in monospace code box
iii. Use the data lawfully — State Bar permitted-use rules,
CCPA/CPRA, no bulk SMS / robocalls / resale, inactive
attorneys excluded at export
- 'For the record' trust block — data sourcing (State Bar public DB +
publicly-indexed firm sites + LA City Active Business Licenses
NAICS 5411), 'directory listing is independent of any commercial
offering,' Stripe PCI disclosure.
Pending path also got Volume strip 'Edition 2026 · Reservation
Pending' + italic-metal 'Reservation noted.' + back-link to /data.
Same iter-25 architectural pattern, four surfaces deep now: /upgrade,
/upgrade/thanks, /signup/welcome, /data/thanks.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Files touched
M src/server/data_market.ts
Diff
commit f10bb428acf303b48b4e38b91418b6aef90be376
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Mon May 4 07:07:24 2026 -0700
Iter 37: /data/thanks editorial confirmation matching iter 25 pattern
Brought /data/thanks paid path to the editorial standard set by
/upgrade/thanks (iter 25). Was eyebrow + h1 + button + bookmark URL —
minimal next to the polished /upgrade/thanks for the same money.
What shipped on the paid path:
- Volume strip 'Edition 2026 · Order Confirmed' (or 'Subscription
Active' for the recurring tier)
- Italic-metal display 'Your data is ready.' (kept; still right)
- Order № receipt strip — DATA-YYYY-MMDD-NNNN format, italic-metal
tabular-nums (matches EZ-YYYY-MMDD-NNNN on /upgrade/thanks). Three
cols: Order №, Logged, Charged ($amount). For subscription tier
shows '$X/mo' and label 'Recurring'.
- 'What's next' 3-cell grid:
i. Download the CSV — flat-noir + champagne-hairline button
ii. Bookmark your download URL — full URL in monospace code box
iii. Use the data lawfully — State Bar permitted-use rules,
CCPA/CPRA, no bulk SMS / robocalls / resale, inactive
attorneys excluded at export
- 'For the record' trust block — data sourcing (State Bar public DB +
publicly-indexed firm sites + LA City Active Business Licenses
NAICS 5411), 'directory listing is independent of any commercial
offering,' Stripe PCI disclosure.
Pending path also got Volume strip 'Edition 2026 · Reservation
Pending' + italic-metal 'Reservation noted.' + back-link to /data.
Same iter-25 architectural pattern, four surfaces deep now: /upgrade,
/upgrade/thanks, /signup/welcome, /data/thanks.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
src/server/data_market.ts | 111 +++++++++++++++++++++++++++++++++++++++-------
1 file changed, 96 insertions(+), 15 deletions(-)
diff --git a/src/server/data_market.ts b/src/server/data_market.ts
index 89d45c8..2988fe1 100644
--- a/src/server/data_market.ts
+++ b/src/server/data_market.ts
@@ -445,13 +445,16 @@ router.get('/data/thanks', async (req, res) => {
let paid = false;
let token = '';
let kind: 'one_time' | 'subscription' = 'one_time';
+ let orderId: number | null = null;
+ let amountPaid = 4900;
if (stripe && sid) {
try {
const s = await stripe.checkout.sessions.retrieve(sid);
- const orderId = s.metadata?.order_id ? parseInt(s.metadata.order_id, 10) : null;
+ orderId = s.metadata?.order_id ? parseInt(s.metadata.order_id, 10) : null;
const subId = (typeof s.subscription === 'string') ? s.subscription : s.subscription?.id;
const custId = (typeof s.customer === 'string') ? s.customer : s.customer?.id;
const isPaid = s.payment_status === 'paid' || s.payment_status === 'no_payment_required';
+ if (typeof s.amount_total === 'number') amountPaid = s.amount_total;
if (orderId && isPaid) {
const r = await query<{ download_token: string; kind: string }>(`
UPDATE data_orders
@@ -482,21 +485,99 @@ router.get('/data/thanks', async (req, res) => {
}
}
const dlUrl = token ? `/data/download/${token}` : '';
+
+ const now = new Date();
+ const pad = (n: number) => String(n).padStart(2, '0');
+ const orderNo = orderId
+ ? `DATA-${now.getFullYear()}-${pad(now.getMonth() + 1)}${pad(now.getDate())}-${String(orderId).padStart(4, '0')}`
+ : `DATA-${now.getFullYear()}-${pad(now.getMonth() + 1)}${pad(now.getDate())}-PEND`;
+ const tstamp = `${pad(now.getHours())}:${pad(now.getMinutes())} PT · ${now.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}`;
+ const dollars = `$${(amountPaid / 100).toFixed(0)}${kind === 'subscription' ? '/mo' : ''}`;
+
const body = paid
- ? `<p class="eyebrow">Order received · payment confirmed</p>
- <h1 class="display">Your data is <em>ready.</em></h1>
- <p class="lede">${kind === 'subscription'
- ? 'Your subscription is active. Bookmark this page — your token is the same key for every monthly refresh.'
- : 'Your one-time export is ready. The download link below is yours; bookmark it for the next 30 days.'}</p>
- <p style="margin:30px 0">
- <a href="${esc(dlUrl)}" class="btn" style="display:inline-block;background:var(--metal);color:var(--noir);padding:16px 28px;font-size:12px;letter-spacing:.18em;text-transform:uppercase;font-weight:500;text-decoration:none;border:1px solid var(--metal)">Download CSV →</a>
- </p>
- <p class="muted">Bookmark this URL — your private download link:<br><code style="background:var(--noir-rise);padding:8px 14px;display:inline-block;margin-top:8px;border:1px solid var(--rule);color:var(--ink-soft);font-size:12px">https://lawyers.agentabrams.com${esc(dlUrl)}</code></p>`
- : `<p class="eyebrow">Almost there</p>
- <h1 class="display">Reservation noted.</h1>
- <p class="lede">If your payment is still processing, give it a moment and refresh. If you cancelled, no charge was made.</p>
- <p><a href="/data">← Back to data</a></p>`;
- res.send(shellHead('Thanks') + body + FOOT);
+ ? `
+ <style>
+ .dt-receipt{margin:32px 0 12px;padding:24px 32px;border:1px solid var(--rule);background:linear-gradient(180deg,rgba(184,153,104,.025),transparent);display:grid;grid-template-columns:repeat(3,1fr);gap:32px}
+ @media (max-width:720px){.dt-receipt{grid-template-columns:1fr;gap:14px;padding:20px 24px}}
+ .dt-r-row{display:flex;flex-direction:column;gap:4px}
+ .dt-r-label{font-size:9px;letter-spacing:.3em;text-transform:uppercase;color:var(--ink-mute);font-weight:500}
+ .dt-r-val{font-family:var(--serif);font-style:italic;color:var(--metal);font-size:18px;font-variant-numeric:tabular-nums;letter-spacing:.02em}
+ .dt-next{margin:64px 0 0;padding:48px 0 0;border-top:1px solid var(--rule)}
+ .dt-next-h{font-family:var(--serif);font-weight:400;font-size:24px;color:var(--ink);margin:0 0 28px;letter-spacing:-.005em}
+ .dt-next-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:0;border-top:1px solid var(--rule);border-bottom:1px solid var(--rule)}
+ @media (max-width:780px){.dt-next-grid{grid-template-columns:1fr}}
+ .dt-next-cell{padding:32px 28px;border-right:1px solid var(--rule);display:flex;flex-direction:column;gap:12px}
+ .dt-next-cell:last-child{border-right:none}
+ @media (max-width:780px){.dt-next-cell{border-right:none;border-bottom:1px solid var(--rule);padding:28px 20px}.dt-next-cell:last-child{border-bottom:none}}
+ .dt-next-num{font-family:var(--serif);font-style:italic;font-weight:300;color:transparent;-webkit-text-stroke:1px var(--metal);font-size:28px;line-height:1;letter-spacing:-.02em}
+ .dt-next-cell h4{font-family:var(--serif);font-weight:400;font-size:18px;line-height:1.25;color:var(--ink);margin:0;letter-spacing:-.005em}
+ .dt-next-cell p{font-size:13px;line-height:1.6;color:var(--ink-mute);margin:0;flex:1}
+ .dt-dl{padding:16px 28px;background:transparent;color:var(--metal-glow);border:1px solid var(--metal);font-size:11px;letter-spacing:.22em;text-transform:uppercase;font-weight:500;text-decoration:none;display:inline-flex;align-items:center;transition:background 280ms ease,color 280ms ease,letter-spacing 280ms ease;align-self:flex-start}
+ .dt-dl:hover{background:var(--metal);color:var(--noir);letter-spacing:.26em}
+ .dt-bookmark{margin:18px 0 0;font-size:12px;color:var(--ink-mute)}
+ .dt-bookmark code{background:var(--noir-rise);padding:8px 14px;display:inline-block;margin-top:6px;border:1px solid var(--rule);color:var(--ink-soft);font-size:12px;letter-spacing:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;word-break:break-all;max-width:100%}
+ .dt-trust{margin-top:48px;padding:24px 28px;border:1px solid var(--rule);background:linear-gradient(180deg,rgba(184,153,104,.018),transparent)}
+ .dt-trust-eyebrow{font-size:9px;letter-spacing:.3em;text-transform:uppercase;color:var(--metal);font-weight:500;margin:0 0 12px}
+ .dt-trust p{font-size:13px;line-height:1.7;color:var(--ink-mute);margin:0;max-width:none}
+ </style>
+ <div class="public-vol">
+ <span class="v-rule"></span>
+ <span class="v-text">Volume I</span>
+ <span class="v-meta">Edition 2026 · ${kind === 'subscription' ? 'Subscription Active' : 'Order Confirmed'}</span>
+ </div>
+ <h1 class="display">Your data is <em>ready.</em></h1>
+ <p class="lede">${kind === 'subscription'
+ ? 'Your subscription is active. The download link below is the same key for every monthly refresh — bookmark it.'
+ : 'Your one-time export is ready. The download link is yours for the next 30 days.'}</p>
+
+ <div class="dt-receipt">
+ <div class="dt-r-row">
+ <span class="dt-r-label">Order №</span>
+ <span class="dt-r-val">${orderNo}</span>
+ </div>
+ <div class="dt-r-row">
+ <span class="dt-r-label">Logged</span>
+ <span class="dt-r-val">${tstamp}</span>
+ </div>
+ <div class="dt-r-row">
+ <span class="dt-r-label">${kind === 'subscription' ? 'Recurring' : 'Charged'}</span>
+ <span class="dt-r-val">${dollars}</span>
+ </div>
+ </div>
+
+ <section class="dt-next">
+ <h3 class="dt-next-h">What's next</h3>
+ <div class="dt-next-grid">
+ <div class="dt-next-cell">
+ <span class="dt-next-num">i.</span>
+ <h4>Download the CSV</h4>
+ <p>Excel-compatible. Columns: Name, Bar #, Firm, Phone, Address, Web. Data exported as of just now.</p>
+ <a class="dt-dl" href="${esc(dlUrl)}">Download →</a>
+ </div>
+ <div class="dt-next-cell">
+ <span class="dt-next-num">ii.</span>
+ <h4>Bookmark your download URL</h4>
+ <p>Your private link is below. The token is unique to you and persists for the duration of your access.</p>
+ <p class="dt-bookmark"><code>https://lawyers.agentabrams.com${esc(dlUrl)}</code></p>
+ </div>
+ <div class="dt-next-cell">
+ <span class="dt-next-num">iii.</span>
+ <h4>Use the data lawfully</h4>
+ <p>State Bar permitted-use rules + CCPA/CPRA apply. No bulk SMS, no robocalls, no resale. We exclude inactive/suspended/deceased attorneys at export time.</p>
+ </div>
+ </div>
+ </section>
+
+ <aside class="dt-trust">
+ <p class="dt-trust-eyebrow">For the record</p>
+ <p>Data is sourced from the State Bar of California's public licensing database and supplemented with firm-level contact information from publicly indexed websites and LA City Active Business Licenses (NAICS 5411). The directory listing is independent of any commercial offering; this is a research-data product, not a placement service. We do not sell consumer leads. Stripe processes the payment; full card data remains with Stripe per their PCI flow.</p>
+ </aside>
+ `
+ : `<div class="public-vol"><span class="v-rule"></span><span class="v-text">Volume I</span><span class="v-meta">Edition 2026 · Reservation Pending</span></div>
+ <h1 class="display">Reservation <em>noted.</em></h1>
+ <p class="lede">If your payment is still processing, give Stripe a few seconds and refresh. If you cancelled, no charge was made.</p>
+ <p style="margin-top:32px"><a href="/data" style="font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--metal);border-bottom:1px solid var(--rule);padding-bottom:3px">← Back to data</a></p>`;
+ res.send(shellHead(paid ? (kind === 'subscription' ? 'Subscription Active' : 'Order Confirmed') : 'Reservation Pending') + body + FOOT);
});
// ─── GET /data/download/:token — CSV export ───────────────────────────────
← e6238ca Iter 36: /find-a-lawyer/thanks — State Bar deep-link + Rule
·
back to Lawyer Directory Builder
·
Iter 38: landing — critical §6155 fixes from cold-eye debate 3fe9d64 →