Skip to content

Commit

Permalink
Merge pull request #243 from hlxsites/237-modal-link
Browse files Browse the repository at this point in the history
Link envelope to contact side modal
  • Loading branch information
rrusher authored Jun 13, 2024
2 parents 317e7ab + a93ae76 commit 35bcf88
Show file tree
Hide file tree
Showing 10 changed files with 260 additions and 128 deletions.
21 changes: 20 additions & 1 deletion blocks/contact-form/contact-form.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@
margin-bottom: 3em;
}

.contact-form.block .contact-details {
display: flex;
flex-direction: row;
gap: 1em;
margin-bottom: 2em;
}

.contact-form.block .profile {
display: flex;
flex-direction: column;
gap: 1em;
}

.contact-form.block .company-name {
font-size: var(--heading-font-size-m);
line-height: var(--line-height-xs);
Expand Down Expand Up @@ -115,7 +128,13 @@
display: flex;
justify-content: flex-start;
margin-bottom: 10px;
cursor: pointer;
}


.contact-form.block form.contact-form .agent div.disclaimer {
font-size: var(--body-font-size-xxs);
line-height: var(--line-height-s);
color: var(--dark-grey);
}

.contact-form.block form.contact-form .agent > div:first-child {
Expand Down
46 changes: 45 additions & 1 deletion blocks/contact-form/contact-form.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { loadScript } from '../../scripts/aem.js';
// import { getEnvelope } from '../../scripts/apis/creg/creg.js';
import { removeSideModal, i18nLookup, getCookieValue } from '../../scripts/util.js';
import { a, div, img } from '../../scripts/dom-helpers.js';

const LOGIN_ERROR = 'There was a problem processing your request.';
const i18n = await i18nLookup();
Expand All @@ -9,6 +11,22 @@ const phoneRegex = /^[+]?[ (]?\d{3}[)]?[-.\s]?\d{3}[-.\s]?\d{4}$/;
// Load reCaptcha script used on all forms.
loadScript('/blocks/contact-form/forms/callback.js');

function getImageURL(jsonString) {
try {
const data = JSON.parse(jsonString);
if (Array.isArray(data) && data.length > 0) {
const imageUrl = new URL(data[0].url);
// Replace the hostname and pathname with the new ones
imageUrl.hostname = 'hsfazpw2storagesf1.blob.core.windows.net';
imageUrl.pathname = `/hsflibrary${imageUrl.pathname}`;
return imageUrl.toString();
}
} catch (error) {
return '/media/images/no-profile-image.png';
}
return null; // Add a return statement at the end of the function
}

/**
* Adds form and cookie values to payload.
*
Expand Down Expand Up @@ -314,7 +332,33 @@ const addForm = async (block) => {
});

const taEl = block.querySelector('textarea');
if (taEl && taEl.placeholder) taEl.placeholder = i18n(taEl.placeholder);
if (taEl?.placeholder) taEl.placeholder = i18n(taEl.placeholder);
if (window.selectedListing) {
// const prop = await findListing();
const prop = window.selectedListing;
// if the listing agent is supposed to be displayed vs the office
if (prop.propertyDetails.listAgentCd) {
const info = block.querySelector('.contact-info');
const pic = getImageURL(prop.listAgent.reAgentDetail.image);
const profile = div({ class: 'profile' }, img({ src: pic, alt: prop.listAgent.recipientName, width: '82px' }));
info.insertAdjacentElement('beforebegin', profile);
const name = block.querySelector('.company-name');
const link = a({ href: '#' }, prop.listAgent.recipientName); // TODO: add link to agent profile
name.replaceChildren(link);
const email = block.querySelector('.company-email a');
email.textContent = prop.listAgent.reAgentDetail.email;
email.href = `mailto:${prop.listAgent.reAgentDetail.email}`;
const phone = block.querySelector('.company-phone a');
phone.textContent = prop.listAgent.reAgentDetail.officeTelephone;
phone.href = `tel:${prop.listAgent.reAgentDetail.officeTelephone}`;
}

taEl.value = `Hi, I would like more information about ${prop.propertyDetails.unparsedAddress}`;

if (window.location.pathname.length === 1) {
block.querySelector('.disclaimer').remove();
}
}

block.style.display = displayValue;

Expand Down
14 changes: 9 additions & 5 deletions blocks/contact-form/forms/contact-property.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
<div class="contact-form">
<div class="form-title">Contact Us</div>
<div class="company-name">Berkshire Hathaway HomeServices<br>Commonwealth Real Estate</div>
<div class="company-email"><a href="mailto:[email protected]" tabindex="-1">[email protected]</a></div>
<div class="company-phone">Direct: <a href="tel:(508) 810-0700" tabindex="-1">(508) 810-0700</a></div>
<div class="contact-details">
<div class="contact-info">
<div class="company-name">Berkshire Hathaway HomeServices<br>Commonwealth Real Estate</div>
<div class="company-email"><a href="mailto:[email protected]" tabindex="-1">[email protected]</a></div>
<div class="company-phone">Direct: <a href="tel:(508) 810-0700" tabindex="-1">(508) 810-0700</a></div>
</div>
</div>
<form id="property-contact" class="contact-form form-elements" method="post" action="/bin/bhhs/websiteTopicServlet">
<div class="message">
<svg class="icon error" role="presentation">
Expand Down Expand Up @@ -53,14 +57,14 @@
</div>
<span class="label">no</span>
</div>
<div class="disclaimer"></div>
</div>
<div class="disclaimer">By providing this information, you are giving permission to Berkshire Hathaway HomeServices, Constellation1, a division of Constellation Web Solutions, Inc., and the members of the Berkshire Hathaway HomeServices real estate network (1) to contact you in response to your specific question or message, and (2) to register you in our system in order to communicate with you about properties for sale or rent in locations of interest to you. For more about how we will use your contact information, review our Privacy Policy.</div>
<div id="captcha-20285" class="g-recaptcha contact-form-captcha">
</div>
<div class="cta">
<div class="button-container">
<button type="submit" class="primary submit" aria-label="Submit contact form">Send</button>
<button class="button cancel" aria-label="Close modal">Cancel</button>
<button class="button secondary cancel" aria-label="Close modal">Cancel</button>
</div>
</div>
</form>
Expand Down
42 changes: 23 additions & 19 deletions blocks/property-listing/property-listing.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,40 @@ import { getMetadata, readBlockConfig } from '../../scripts/aem.js';
import { render as renderCards } from '../shared/property/cards.js';
import Search from '../../scripts/apis/creg/search/Search.js';
import { propertySearch } from '../../scripts/apis/creg/creg.js';
import {
a, div, p, span,
} from '../../scripts/dom-helpers.js';

export default async function decorate(block) {
// Find and process list type configurations.
const config = readBlockConfig(block);
const search = await Search.fromBlockConfig(config);
search.franchiseeCode = getMetadata('office-id');
const searchUrl = `search?${search.asCregURLSearchParameters()}`;

if (config.title) {
block.innerHTML = `
<div class="header">
<div>
<span>${config.title}</span>
</div>
</div>
`;
if (config['link-text']) {
const div = document.createElement('div');
const url = config['link-url'] || '';
div.innerHTML = `
<p class="button-container">
<a href="${url}" aria-label="${config['link-text'] || 'See More'}">${config['link-text'] || 'See More'}</a>
</p>`;
block.querySelector('.header').append(div);
const blockTitle = div({ class: 'header' },
div(
span(config.title),
),
);
block.replaceChildren(blockTitle);

if (config.link) {
const moreBtn = div(
p({ class: 'button-container' },
a({ href: config['link-url'] || searchUrl, 'aria-label': config.link || 'See More', class: 'button secondary' },
config.link || 'See More',
),
),
);
block.querySelector('.header').append(moreBtn);
}
} else {
block.innerHTML = '';
}

const search = await Search.fromBlockConfig(config);
search.franchiseeCode = getMetadata('office-id');
const list = document.createElement('div');
list.classList.add('property-list-cards', `rows-${Math.floor(search.pageSize / 8)}`);
const list = div({ class: `property-list-cards rows-${Math.floor(search.pageSize / 8)}` });
block.append(list);
propertySearch(search).then((results) => {
renderCards(list, results.properties);
Expand Down
174 changes: 94 additions & 80 deletions blocks/shared/property/cards.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { decorateFormLinks } from '../../../scripts/scripts.js';
import {
a, div, domEl, img, p, span,
} from '../../../scripts/dom-helpers.js';

function createImage(listing) {
if (listing.SmallMedia?.length > 0) {
return `<img src="${listing.SmallMedia[0].mediaUrl}" alt="${listing.StreetName}" loading="lazy" class="property-thumbnail">`;
const tempImg = img({
src: listing.SmallMedia[0].mediaUrl, alt: listing.StreetName, loading: 'lazy', class: 'property-thumbnail',
});
return tempImg;
}
return '<div class="property-no-available-image"><span>no images available</span></div>';
return div({ class: 'property-no-available-image' }, span('no images available'));
}

export function createCard(listing) {
Expand All @@ -27,98 +33,106 @@ export function createCard(listing) {
specs.push(`${listing.LivingArea} ${listing.LivingAreaUnits}`);
}

const item = document.createElement('div');
item.classList.add('listing-tile');
let classes = 'listing-tile';
if (listing.OpenHouses?.length > 0) {
item.classList.add('has-open-houses');
classes += ' has-open-houses';
}

if (listing.FeaturedListing) {
item.classList.add('is-featured');
classes += ' is-featured';
}

if (listing.PdpPath.includes('LuxuryTheme=true')) {
item.classList.add('is-luxury');
classes += ' is-luxury';
}
const applicationType = listing.ListingType && listing.ListingType === 'For Rent' ? `<span class="property-label new-listing">${listing.ListingType}</span>` : '';

if (listing.ClosedDate !== '01/01/0001') {
item.classList.add('is-sold');
classes += 'is-sold';
listing.mlsStatus = 'Closed';
}

item.innerHTML = `
<a href="${detailsPath}" rel="noopener" aria-labelledby="listing-${listing.ListingId}-address">
<div class="listing-image-container">
<div class="property-image">
${createImage(listing)}
</div>
<div class="image-position-top">
<div class="property-labels">
<div class="property-label luxury">Luxury Collection</div>
<div class="property-label open-house">
<span class="icon icon-openhouse"></span>
Open House
</div>
</div>
</div>
<div class="image-position-bottom">
<div class="property-labels">
<span class="property-label featured">Featured Listing</span>
${applicationType}
<span class="property-label">${listing.mlsStatus}</span>
</div>
<div class="property-price">
<p>${listing.ListPriceUS}</p>
</div>
</div>
</div>
</a>
<div class="property-details">
<div class="property-info-wrapper">
<div class="property-info">
<div class="sold-date">Closed: ${listing.ClosedDate}</div>
<div id="listing-${listing.ListingId}-address" class="address">
${listing.StreetName}
<br>
${listing.City}, ${listing.StateOrProvince} ${listing.PostalCode}
</div>
<div class="specs">${specs.join(' / ')}</div>
</div>
</div>
<div class="property-buttons">
<div class="buttons-row-flex">
<a aria-label="Contact us about ${listing.StreetName}" href="#" class="button-property">
<span class="icon icon-envelope">
<img data-icon-name="envelope" src="/icons/envelope.svg" loading="lazy" alt="envelope">
</span>
<span class="icon icon-envelopedark">
<img data-icon-name="envelopedark" src="/icons/envelopedark.svg" loading="lazy" alt="envelope">
</span>
</a>
<a aria-label="Save ${listing.StreetName} to saved properties." href="#" class="button-property">
<span class="icon icon-heartempty">
<img data-icon-name="heartempty" src="/icons/heartempty.svg" loading="lazy" alt="heart">
</span>
<span class="icon icon-heartemptydark">
<img data-icon-name="heartempty" src="/icons/heartemptydark.svg" loading="lazy" alt="heart">
</span>
</a>
</div>
</div>
</div>
<hr>
<div class="extra-info">
<div>
<div class="courtesy-info">Listing courtesy of: ${listing.CourtesyOf}</div>
<div class="courtesy-provided">Listing provided by: ${listing.listAor}</div>
</div>
<div class="listing-aor ${listing.listAor.toLowerCase()}">
<img class="rimls-image" src="/styles/images/rimls_logo.jpg" alt="Disclaimer Logo Image" loading="lazy" height="20" width="33">
</div>
</div>
`;
return item;
const newEl = div({ class: classes },
a({ href: detailsPath, rel: 'noopener', 'aria-labelledby': `listing-${listing.ListingId}-address` },
div({ class: 'listing-image-container' },
div({ class: 'property-image' }, createImage(listing)),
div({ class: 'image-position-top' },
div({ class: 'property-labels' },
div({ class: 'property-label luxury' }, 'Luxury Collection'),
div({ class: 'property-label open-house' },
span({ class: 'icon icon-openhouse' }, 'Open House'),
),
),
),
div({ class: 'image-position-bottom' },
div({ class: 'property-labels' },
span({ class: 'property-label featured' }, 'Featured Listing'),
applicationType,
span({ class: 'property-label' }, listing.mlsStatus),
),
div({ class: 'property-price' },
p(listing.ListPriceUS),
),
),
),
),
div({ class: 'property-details' },
div({ class: 'property-info-wrapper' },
div({ class: 'property-info' },
div({ class: 'sold-date' }, `Closed: ${listing.ClosedDate}`),
div({ id: `listing-${listing.PropId}-address`, class: 'address' },
listing.StreetName,
domEl('br'),
`${listing.City}, `,
`${listing.StateOrProvince} `,
listing.PostalCode,
),
div({ class: 'specs' }, specs.join(' / ')),
),
),
div({ class: 'property-buttons' },
div({ class: 'buttons-row-flex' },
a({ 'aria-label': `Contact us about ${listing.StreetName}`, href: '/fragments/contact-property-form', class: 'button-property' },
span({ class: 'icon icon-envelope' },
img({
'data-icon-name': 'envelope', src: '/icons/envelope.svg', loading: 'lazy', alt: 'envelope',
}),
),
span({ class: 'icon icon-envelopedark' },
img({
'data-icon-name': 'envelopedark', src: '/icons/envelopedark.svg', loading: 'lazy', alt: 'envelope',
}),
),
),
a({ 'aria-label': `Save ${listing.StreetName} to saved properties.`, href: '#', class: 'button-property' },
span({ class: 'icon icon-heartempty' },
img({
'data-icon-name': 'heartempty', src: '/icons/heartempty.svg', loading: 'lazy', alt: 'heart',
}),
),
span({ class: 'icon icon-heartemptydark' },
img({
'data-icon-name': 'heartempty', src: '/icons/heartemptydark.svg', loading: 'lazy', alt: 'heart',
}),
),
),
),
),
),
domEl('hr'),
div({ class: 'extra-info' },
div(
div({ class: 'courtesy-info' }, `Listing courtesy of: ${listing.CourtesyOf}`),
div({ class: 'courtesy-provided' }, `Listing provided by: ${listing.listAor}`),
),
div({ class: `listing-aor ${listing.listAor.toLowerCase()}` },
img({
class: 'rimls-image', src: '/styles/images/rimls_logo.jpg', alt: 'Disclaimer Logo Image', loading: 'lazy', height: '20', width: '33',
}),
),
),
);
return newEl;
}

/**
Expand Down
Loading

0 comments on commit 35bcf88

Please sign in to comment.