Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Property Details Page: Socioeconomic data accordion items #116

Merged
merged 11 commits into from
May 23, 2024
Merged
176 changes: 176 additions & 0 deletions blocks/economic-data/economic-data.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
.economic-data.block {
margin: 0;
padding: 20px;
box-sizing: border-box;
}

.economic-data .accordion-header {
border-top: 1px solid var(--grey);
cursor: pointer;
padding: 16px 30px 16px 0;
position: relative;
display: inline-block;
font-family: var(--font-family-georgia);
font-weight: var(--font-weight-semibold);
line-height: 26px;
margin: 0 5px 0 0;
font-size: 22px;
width: 100%;
}

.economic-data .accordion .accordion-header::after {
border-color: var(--body-color) transparent transparent transparent;
border-style: solid;
border-width: 6px 5px 0;
content: '';
margin-top: -5px;
position: absolute;
right: 8px;
top: 50%;
transition: transform .3s linear;
transform: rotate(0);
}

.economic-data .accordion .accordion-header:not(.active)::after {
transform: rotate(90deg);
transition: transform .3s linear;
}

.economic-data .accordion-content {
display: none;
padding-bottom: 60px;
}

.economic-data .accordion-header.active + .accordion-content {
display: block;
}

.economic-data .container {
display: flex;
flex-direction: column;
}

.economic-data .row {
display: flex;
flex-wrap: wrap;
border-bottom: 1px solid #ccc;
padding: 10px 0;
}

.economic-data.block .accordion-content .row:last-child {
border-bottom: none;
}

.economic-data .cell {
padding: 10px 10px 10px 0;
box-sizing: border-box;
}

.economic-data .cell-header {
font-weight: bold;
text-transform: uppercase;
font-size: var(--body-font-size-xs);
line-height: var(--line-height-xs);
letter-spacing: var(--letter-spacing-xs);
}

.economic-data .cell-1 {
width: 100%;
text-transform: uppercase;
font-size: 14px;
}

.economic-data .cell-1.cell-header {
padding: 0;
}

.economic-data .cell-2, .economic-data .cell-3, .economic-data .cell-4 {
width: 33.33%;
}

.economic-data .progress-bar {
width: calc(100% - 60px);
background-color: #f3f3f3;
height: 5px;
margin-left: 50px;
margin-top: -12px;
position: relative;
}

.economic-data .progress-owner, .progress-renter {
height: 100%;
position: absolute;
top: 0;
}

.economic-data .progress-owner {
background-color: var(--primary-color);
left: 0;
}

.economic-data .progress-renter {
background-color: var(--light-grey);
right: 0;
}

.economic-data .tooltip {
position: relative;
display: inline-block;
height: 19px;
width: 19px;
margin-left: 5px;
}

.economic-data .tooltip .icon-info-circle-dark {
display: none;
}

.economic-data .tooltip .tooltiptext {
visibility: hidden;
width: 290px;
background-color: var(--black);
color: var(--white);
text-align: left;
padding: 14px 18px;
position: absolute;
z-index: 1;
top: 100%;
left: 0;
margin: 12px 0 0 -10px;
font-family: var(--font-family-proxima);
font-size: var(--body-font-size-s);
letter-spacing: var(--letter-spacing-s);
line-height: var(--line-height-s);
}

.economic-data .tooltip:hover .icon-info-circle {
display: none;
}

.economic-data .tooltip:hover .icon-info-circle-dark {
display: block;
}

.economic-data .tooltip:hover .tooltiptext {
visibility: visible;
}

.economic-data .tooltip .tooltiptext::before {
content: '';
position: absolute;
bottom: 100%;
left: 8px;
border-width: 10px;
border-style: solid;
border-color: transparent transparent var(--black) transparent;
}

@media (min-width: 900px) {
.economic-data .cell-1 {
width: 25%;
}

.economic-data .cell-2, .economic-data .cell-3, .economic-data .cell-4 {
width: 25%;
}
}
174 changes: 174 additions & 0 deletions blocks/economic-data/economic-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import { getDetails, getEconomicDetails } from '../../scripts/apis/creg/creg.js';
import { div, span } from '../../scripts/dom-helpers.js';
import { decorateIcons } from '../../scripts/aem.js';

const keys = [
'ListPriceUS',
'StreetName',
'City',
'StateOrProvince',
'PostalCode',
'Latitude',
'Longitude',
'LotSizeAcres',
'LotSizeSquareFeet',
'LivingAreaUnits',
'Media',
'SmallMedia',
'PropId',
'OpenHouses',
'CourtesyOf',
];

function pick(obj, ...args) {
return args.reduce((res, key) => ({ ...res, [key]: obj[key] }), { });
}

function toggleAccordion(event) {
const content = event.target;
content.classList.toggle('active');
}

/**
* Retrieves the property ID from the current URL path.
* @returns {string|null} The property ID if found in the URL path, or null if not found.
*/
function getPropIdFromPath() {
const url = window.location.pathname;
const match = url.match(/pid-(\d+)/);
if (match && match[1]) {
return match[1];
}
return null;
}

async function getPropertyByPropId(propId) {
const resp = await getDetails(propId);
return resp[0];
}

async function getSocioEconomicData(latitude, longitude) {
const resp = await getEconomicDetails(latitude, longitude);
return resp[0];
}

function getHeaderLabels(title) {
switch (title.toLowerCase()) {
case 'occupancy':
return 'Occupancy';
case 'housing trends':
return 'Housing Trends';
case 'economic data':
return 'Economic Data';
default:
return 'Untitled';
}
}

function getColumnHeader(title, index) {
switch (title.toLowerCase()) {
case 'occupancy':
return ['Owned', 'Rented', 'Vacant'][index - 1];
case 'housing trends':
return ['Home Appreciation', 'Median Age'][index - 1];
case 'economic data':
return ['Median House. Income', 'Unemployment', 'Cost of Living Index'][index - 1];
default:
return '';
}
}

function getDataValue(item, title, index) {
switch (title.toLowerCase()) {
case 'occupancy':
if (index === 1) {
return `${item.ownerOccupiedPercent}%`;
}
if (index === 2) {
return `${item.renterOccupiedPercent}%`;
}
return `${item.vacancyPercent}%`;
case 'housing trends':
if (index === 1) {
return `${item.homeValueAppreciationPercent}%`;
}
return `${item.medianHomeAge}`;
case 'economic data':
if (index === 1) {
return `${item.medianIncome}`;
}
return `${item.unemploymentPercent}%`;
default:
return '';
}
}

function generateDataTable(block, title, socioEconData) {
// Create the accordion structure
const accordion = div({ class: 'accordion' },
div({ class: 'accordion-header', onclick: (e) => toggleAccordion(e) }, getHeaderLabels(title), div({ class: 'tooltip' },
span({ class: 'icon icon-info-circle' }),
span({ class: 'icon icon-info-circle-dark' }),
span({ class: 'tooltiptext' }, `${socioEconData.citation}`),
),
),
div({ class: 'accordion-content' },
div({ id: `${title.toLowerCase().replace(' ', '-')}-data-container`, class: 'container', role: 'grid' }),
),
);
block.appendChild(accordion);

const container = document.getElementById(`${title.toLowerCase().replace(' ', '-')}-data-container`);

// Create header row
const headerRow = div({ class: 'row', role: 'row' },
div({ class: 'cell cell-1 cell-header', role: 'columnheader' }),
div({ class: 'cell cell-2 cell-header', role: 'columnheader' }, getColumnHeader(title, 1)),
div({ class: 'cell cell-3 cell-header', role: 'columnheader' }, getColumnHeader(title, 2)),
div({ class: 'cell cell-4 cell-header', role: 'columnheader' }, getColumnHeader(title, 3) ? getColumnHeader(title, 3) : ''),
);
container.appendChild(headerRow);

// Create data rows
socioEconData.data.forEach((item) => {
const dataRow = div({ class: 'row', role: 'row' },
div({ class: 'cell cell-1', role: 'cell' },
div({ role: 'presentation' }, `${item.level.charAt(0).toUpperCase() + item.level.slice(1)}: ${item.label}`),
),
div({ class: 'cell cell-2', role: 'cell' },
getDataValue(item, title, 1),
title.toLowerCase() === 'occupancy'
? div({ class: 'progress-bar' },
span({ class: 'progress-owner', style: `width: ${item.ownerOccupiedPercent}%` }),
span({ class: 'progress-renter', style: `width: ${100 - item.ownerOccupiedPercent}%` }),
) : '',
),
div({ class: 'cell cell-3', role: 'cell' }, getDataValue(item, title, 2)),
div({ class: 'cell cell-4', role: 'cell' }, title.toLowerCase() === 'housing trends' ? '' : getDataValue(item, title, 3)),
);

container.appendChild(dataRow);
});
}

export default async function decorate(block) {
let property = {};
let propId = getPropIdFromPath(); // assumes the listing page pathname ends with the propId
// TODO: remove this test propId
if (!propId) propId = '370882966';

const propertyData = await getPropertyByPropId(propId);
if (propertyData) {
property = pick(propertyData, ...keys);
if (property.Latitude && property.Longitude) {
const socioEconData = await getSocioEconomicData(property.Latitude, property.Longitude);
if (socioEconData) {
generateDataTable(block, 'Occupancy', socioEconData);
generateDataTable(block, 'Housing Trends', socioEconData);
generateDataTable(block, 'Economic Data', socioEconData);
}
}
}
decorateIcons(block);
window.property = property;
}
2 changes: 1 addition & 1 deletion blocks/info-mouseover/info-mouseover.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default async function decorate(block) {
const heading = block.closest('.section').querySelector('h1,h2,h3,h4,h5,h6');

const icon = document.createElement('span');
icon.classList.add('icon', 'icon-info_circle');
icon.classList.add('icon', 'icon-info-circle');

positionIcon(heading, icon);
block.append(icon);
Expand Down
2 changes: 1 addition & 1 deletion blocks/profile/profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ function showNotification(type, iconHtml, message, message2) {
}

function showError(err) {
showNotification('error', '<img src="/icons/info_circle.svg" aria-hidden="true" alt="Error" class="info-circle">', i18n('There was a problem processing your request.'), i18n(err));
showNotification('error', '<img src="/icons/info-circle.svg" aria-hidden="true" alt="Error" class="info-circle">', i18n('There was a problem processing your request.'), i18n(err));
}

function showSuccess(message) {
Expand Down
1 change: 1 addition & 0 deletions icons/info_circle_dark.svg → icons/info-circle-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
Loading
Loading