← back to NationalPaperHangers
views/public/installer.ejs
286 lines
<%- include('../partials/head', { title }) %>
<%- include('../partials/header') %>
<%
function safeWebsite(u) {
if (!u) return null;
try { var x = new URL(u); return (x.protocol === 'http:' || x.protocol === 'https:') ? x.toString() : null; }
catch (e) { return null; }
}
var safeSiteUrl = safeWebsite(installer.website);
%>
<article class="installer-profile">
<%
var _calendarTier = ['pro','signature','enterprise'].indexOf(installer.tier) !== -1;
var _selfBookable = _calendarTier && installer.subscription_status === 'active';
var _depositCents = parseInt(process.env.NPH_DEFAULT_DEPOSIT_CENTS || '9900', 10);
var _depositLabel = '$' + (_depositCents / 100).toFixed(0);
var _feeBps = parseInt(process.env.NPH_PLATFORM_FEE_BPS || '2500', 10);
var _feePct = Math.round(_feeBps / 100);
%>
<% if (_selfBookable) { %>
<aside class="reserve-banner" role="region" aria-label="Reserve a visit">
<div class="reserve-banner-inner">
<div class="reserve-copy">
<p class="reserve-kicker">Reserve a visit · <%= _depositLabel %> deposit</p>
<p class="reserve-body">Pay through NPH — your share goes straight to <%= installer.business_name %>. NPH retains a <%= _feePct %>% lead-coordination fee. The installation contract is between you and <%= installer.business_name %> directly.</p>
<p class="reserve-fineprint" style="margin:6px 0 0;font-size:11px;color:var(--fg-muted);line-height:1.5">Verify CA contractor licenses at <a href="https://search.cslb.ca.gov/" target="_blank" rel="noopener">search.cslb.ca.gov</a> before signing.</p>
</div>
<a href="/installer/<%= installer.slug %>/book" class="btn btn-primary btn-lg reserve-cta">Book a consultation →</a>
</div>
</aside>
<% } %>
<% var _heroImg = (portfolio.length === 0) ? pickSegmentImage(installer) : null; %>
<% if (_heroImg) {
var _attr = imageAttribution(_heroImg.file);
var _firstSeg = String((installer.market_segments && installer.market_segments[0]) || 'interior');
%>
<div class="installer-hero-image">
<img src="<%= _heroImg.file %>" alt="Wallcovering installation, <%= _firstSeg.replace(/_/g,' ') %>" loading="eager" decoding="async">
<% if (_attr) { %>
<a class="photo-credit" href="<%= _attr.source_url %>" target="_blank" rel="noopener">
Photo<% if (_attr.creator) { %>: <%= _attr.creator.slice(0, 60) %><% } %> · <%= _attr.license %> · <%= _attr.source %>
</a>
<% } %>
</div>
<% } %>
<header class="profile-hero">
<div class="profile-hero-inner">
<p class="kicker"><%= installer.city %>, <%= installer.state %> · est. <%= installer.founded_year || '—' %></p>
<h1 class="display-sm"><%= installer.business_name %></h1>
<% if (installer.headline) { %><p class="profile-headline"><%= installer.headline %></p><% } %>
<div class="profile-badges">
<% if (installer.claim_status === 'unclaimed') { %>
<span class="directory-badge" title="Public directory listing — studio has not yet claimed.">Directory listing</span>
<% } %>
<% if (installer.verified) { %><span class="verified-badge">Verified</span><% } %>
<% if (installer.insurance_on_file) { %><span class="badge">Insurance on file</span><% } %>
<% if (installer.travel_available) { %><span class="badge">Travels for projects</span><% } %>
<% if (installer.tier === 'signature' || installer.tier === 'enterprise') { %><span class="signature-badge">Signature</span><% } %>
<% if (installer.claim_status !== 'unclaimed') { %><span class="badge">Responds in < <%= installer.response_time_hours %>h</span><% } %>
</div>
<% if (installer.claim_status === 'unclaimed') { %>
<div class="callout" style="margin:20px 0">
<strong>Trade buyers are finding this studio on NPH.</strong>
If you operate <%= installer.business_name %>, claim your listing in 2 minutes to enable direct bookings, the Verified badge, and reply-tracking on inbound leads.
<a href="/installer/<%= installer.slug %>/claim" class="btn btn-primary btn-sm" style="margin-left:8px">Claim this listing</a>
<p class="muted" style="margin:8px 0 0;font-size:13px">Seeded from <%= installer.source_name === 'wia' ? 'the WIA public directory' : 'a public source' %>. <a href="mailto:info@nationalpaperhangers.com?subject=Opt-out%3A%20<%= encodeURIComponent(installer.business_name) %>">Request removal →</a></p>
</div>
<% } %>
<div class="profile-actions">
<% if (installer.claim_status === 'unclaimed') { %>
<% if (safeSiteUrl) { %><a href="<%= safeSiteUrl %>" target="_blank" rel="noopener" class="btn btn-primary btn-lg">Visit studio site ↗</a><% } %>
<% if (installer.instagram_handle) { %><a href="https://instagram.com/<%= encodeURIComponent(installer.instagram_handle) %>" target="_blank" rel="noopener" class="btn btn-ghost btn-lg">@<%= installer.instagram_handle %></a><% } %>
<% } else { %>
<a href="/installer/<%= installer.slug %>/book" class="btn btn-primary btn-lg">Book a consultation</a>
<% if (safeSiteUrl) { %><a href="<%= safeSiteUrl %>" target="_blank" rel="noopener" class="btn btn-ghost">Visit studio site ↗</a><% } %>
<% if (installer.instagram_handle) { %><a href="https://instagram.com/<%= encodeURIComponent(installer.instagram_handle) %>" target="_blank" rel="noopener" class="btn btn-ghost">@<%= installer.instagram_handle %></a><% } %>
<% } %>
</div>
</div>
</header>
<div class="profile-body">
<section class="profile-bio">
<h2 class="section-title">About the studio</h2>
<p><%= installer.bio %></p>
</section>
<aside class="profile-sidebar">
<h3>At a glance</h3>
<dl>
<dt>Service radius</dt>
<dd><%= installer.service_radius_miles %> miles<%= installer.travel_available ? ' · travels for projects' : '' %></dd>
<% if (installer.team_size) { %>
<dt>Team</dt><dd><%= installer.team_size %> installer<%= installer.team_size === 1 ? '' : 's' %></dd>
<% } %>
<% if ((installer.market_segments || []).length) { %>
<dt>Segments</dt><dd><%= installer.market_segments.map(s => String(s||'').replace(/_/g,' ')).filter(Boolean).join(', ') %></dd>
<% } %>
<% if ((installer.materials || []).length) { %>
<dt>Materials</dt><dd><%= installer.materials.map(s => String(s||'').replace(/_/g,' ')).filter(Boolean).join(', ') %></dd>
<% } %>
<% if ((installer.brands_handled || []).length) { %>
<dt>Brands installed</dt><dd><%= installer.brands_handled.join(', ') %></dd>
<% } %>
<% if ((installer.accreditations || []).length) { %>
<dt>Accreditations</dt><dd><%= installer.accreditations.join(', ') %></dd>
<% } %>
</dl>
<%
var eq = installer.equipment;
var hasEq = eq && (eq.max_reach_ft || eq.lift_type || eq.paper_table || eq.vehicle || eq.dust_extraction || eq.notes);
var liftLabel = {
extension_ladder: 'Extension ladder',
scaffold: 'Scaffold',
scissor_lift: 'Scissor lift',
boom_lift: 'Boom lift'
};
var tableLabel = {
none: 'No dedicated table',
folding: 'Folding table',
dedicated_60: 'Dedicated 60" pasting table',
dedicated_72_plus: 'Dedicated 72"+ pasting table'
};
var vehicleLabel = { van: 'Van', box_truck: 'Box truck', trailer: 'Trailer-equipped' };
%>
<% if (hasEq) { %>
<h3 style="margin-top:24px">Studio capacity</h3>
<dl>
<% if (eq.max_reach_ft) { %><dt>Reach</dt><dd>Up to <%= eq.max_reach_ft %> ft</dd><% } %>
<% if (eq.lift_type) { %><dt>Lift</dt><dd><%= liftLabel[eq.lift_type] || eq.lift_type %></dd><% } %>
<% if (eq.paper_table) { %><dt>Pasting</dt><dd><%= tableLabel[eq.paper_table] || eq.paper_table %></dd><% } %>
<% if (eq.vehicle) { %><dt>Vehicle</dt><dd><%= vehicleLabel[eq.vehicle] || eq.vehicle %></dd><% } %>
<% if (eq.dust_extraction) { %><dt>Dust</dt><dd>HEPA extraction on-site</dd><% } %>
<% if (eq.notes) { %><dt>Notes</dt><dd><%= eq.notes %></dd><% } %>
</dl>
<% } %>
<% if (typeof credentials !== 'undefined' && credentials && credentials.length) {
var _credLabel = {
brand_trained: 'trained',
brand_certified: 'certified',
brand_approved: 'approved',
manufacturer_partner: 'partner',
trade_member: 'member'
};
%>
<h3 style="margin-top:24px">Brand credentials</h3>
<ul class="credential-list" style="list-style:none;padding:0;margin:0">
<% credentials.forEach(function(c){ %>
<li style="padding:8px 0;border-bottom:1px solid var(--border)">
<strong><%= c.brand %></strong>
<span class="muted">· <%= _credLabel[c.credential_type] || c.credential_type %><% if (c.year_issued) { %> <%= c.year_issued %><% } %></span>
<% if (c.certificate_url) { %>
<a href="<%= c.certificate_url %>" target="_blank" rel="noopener" style="font-size:12px;margin-left:6px">cert ↗</a>
<% } %>
</li>
<% }); %>
</ul>
<% } %>
<% if (typeof acceptance !== 'undefined' && acceptance) { %>
<h3 style="margin-top:24px">Selectivity</h3>
<p style="margin:0">
<strong>Accepts <%= acceptance.rate %>%</strong> of inquiries
<span class="muted">(<%= acceptance.accepted %> taken / <%= acceptance.declined %> declined, last 12 mo)</span>
</p>
<p class="muted" style="font-size:12px;margin:6px 0 0">A studio booked solid enough to be selective.</p>
<% } %>
<%- include('../partials/paper-contributions') %>
</aside>
</div>
<%- include('../partials/coi-request') %>
<%- include('../partials/call-installer') %>
<% if (portfolio.length > 0) { %>
<section class="profile-portfolio">
<h2 class="section-title">Selected projects</h2>
<p class="muted" style="margin:-12px 0 18px;font-size:13px">Tap <em>Seams</em>, <em>Corners</em>, or <em>Ceiling</em> on any project to see craft detail — where the difference shows.</p>
<div class="portfolio-grid">
<% portfolio.forEach(function(p, idx){
var shots = [
{ key: 'hero', label: 'Project', url: p.image_url },
{ key: 'seam', label: 'Seams', url: p.detail_seam_url },
{ key: 'corner', label: 'Corners', url: p.detail_corner_url },
{ key: 'ceiling', label: 'Ceiling', url: p.detail_ceiling_url }
].filter(s => s.url);
%>
<article class="portfolio-card portfolio-card-tabbed" data-portfolio-card="<%= idx %>">
<div class="portfolio-image-wrap">
<% if (shots.length === 0) { %>
<span class="portfolio-image-placeholder"><%= (p.brand || '').slice(0,2).toUpperCase() %></span>
<% } else { %>
<% shots.forEach(function(s, i){ %>
<img class="portfolio-shot <%= i === 0 ? 'is-active' : '' %>"
data-shot="<%= s.key %>"
src="<%= s.url %>"
alt="<%= p.title %> — <%= s.label %>"
loading="lazy">
<% }); %>
<% } %>
</div>
<% if (shots.length > 1) { %>
<nav class="portfolio-tabs" aria-label="Project detail">
<% shots.forEach(function(s, i){ %>
<button type="button"
class="portfolio-tab <%= i === 0 ? 'is-active' : '' %>"
data-shot-target="<%= s.key %>"
data-card="<%= idx %>"><%= s.label %></button>
<% }); %>
</nav>
<% } %>
<h3><%= p.title %></h3>
<p class="portfolio-meta">
<%= [p.city, p.state, p.year].filter(Boolean).join(' · ') %>
<% if (p.brand) { %> · <%= p.brand %><% } %>
</p>
<% if (p.description) { %><p class="portfolio-desc"><%= p.description %></p><% } %>
</article>
<% }); %>
</div>
</section>
<% } %>
<%- include('../partials/social-videos') %>
<% if (reviews.length > 0) { %>
<section class="profile-reviews">
<h2 class="section-title">Verified reviews</h2>
<div class="reviews-grid">
<% reviews.forEach(function(r){ %>
<article class="review-card">
<div class="review-rating"><%= '★'.repeat(r.rating) %><%= '☆'.repeat(5 - r.rating) %></div>
<% if (r.title) { %><h4><%= r.title %></h4><% } %>
<p><%= r.body %></p>
<p class="review-author"><%= r.customer_name || 'Verified client' %><% if (r.verified) { %> · Verified<% } %></p>
</article>
<% }); %>
</div>
</section>
<% } %>
<section class="profile-cta">
<h2 class="display-sm">Ready to book <%= installer.business_name %>?</h2>
<a href="/installer/<%= installer.slug %>/book" class="btn btn-primary btn-lg">Open the calendar</a>
</section>
<%
var _ldBase = (typeof publicUrl !== 'undefined' && publicUrl) ? publicUrl.replace(/\/+$/, '') : 'https://www.nationalpaperhangers.com';
var _ld = {
'@context': 'https://schema.org',
'@type': 'LocalBusiness',
name: installer.business_name,
description: (installer.bio || '').slice(0, 500),
url: _ldBase + '/installer/' + installer.slug,
address: {
'@type': 'PostalAddress',
addressLocality: installer.city || undefined,
addressRegion: installer.state || undefined,
postalCode: installer.zip || undefined,
addressCountry: installer.country || 'US'
},
knowsAbout: (installer.materials || []).map(function(m){ return String(m || '').replace(/_/g,' '); }).filter(Boolean),
hasCredential: (installer.accreditations || [])
};
if (safeSiteUrl) _ld.sameAs = [safeSiteUrl];
%>
<script type="application/ld+json"><%- JSON.stringify(_ld) %></script>
<script type="application/ld+json"><%- JSON.stringify({
'@context':'https://schema.org','@type':'BreadcrumbList',
itemListElement: [
{ '@type':'ListItem', position:1, name:'Find an installer', item: _ldBase + '/find' },
{ '@type':'ListItem', position:2, name: installer.business_name, item: _ldBase + '/installer/' + installer.slug }
]
}) %></script>
</article>
<%- include('../partials/footer') %>
<script src="/js/portfolio-tabs.js" defer></script>