2019-01-19 13:47:08 -05:00
|
|
|
import urlapi from 'url';
|
2018-10-01 07:45:33 -04:00
|
|
|
import React, { Fragment } from 'react';
|
2018-09-30 19:13:01 -04:00
|
|
|
import { Link, NavLink } from 'react-router-dom';
|
2019-05-27 13:26:29 -04:00
|
|
|
import PropTypes from 'prop-types';
|
2018-09-09 17:22:44 -04:00
|
|
|
|
2018-09-11 15:59:59 -04:00
|
|
|
import Sidebar from './sidebar';
|
|
|
|
import Tooltip from './tooltip';
|
2018-09-13 15:41:42 -04:00
|
|
|
import InfoBox from './info-box';
|
2018-11-13 05:45:35 -05:00
|
|
|
import { EditIcon } from './icons';
|
2018-09-11 15:59:59 -04:00
|
|
|
|
2018-10-03 16:47:49 -04:00
|
|
|
import CONFIG from './fields-config.json';
|
2018-09-30 19:32:24 -04:00
|
|
|
|
2018-10-03 16:47:49 -04:00
|
|
|
const BuildingView = (props) => {
|
|
|
|
if (!props.building_id){
|
|
|
|
return (
|
|
|
|
<Sidebar title="Building Not Found">
|
|
|
|
<InfoBox msg="We can't find that one anywhere - try the map again?" />
|
|
|
|
<div className="buttons-container with-space">
|
2018-11-29 17:00:53 -05:00
|
|
|
<Link to="/view/age.html" className="btn btn-secondary">Back to maps</Link>
|
2018-10-03 16:47:49 -04:00
|
|
|
</div>
|
|
|
|
</Sidebar>
|
|
|
|
);
|
|
|
|
}
|
2019-05-10 09:00:20 -04:00
|
|
|
const cat = props.match.params.cat;
|
2018-10-03 16:47:49 -04:00
|
|
|
return (
|
2019-05-27 11:31:48 -04:00
|
|
|
<Sidebar title={'Data available for this building'} back={`/view/${cat}.html`}>
|
2018-10-03 16:47:49 -04:00
|
|
|
{
|
2019-05-27 13:26:29 -04:00
|
|
|
CONFIG.map(section => (
|
2018-10-03 16:47:49 -04:00
|
|
|
<DataSection
|
2019-05-27 13:26:29 -04:00
|
|
|
key={section.slug} cat={cat}
|
2018-10-03 16:47:49 -04:00
|
|
|
building_id={props.building_id}
|
2019-05-27 13:26:29 -04:00
|
|
|
{...section}>
|
2018-10-03 16:47:49 -04:00
|
|
|
{
|
2019-05-27 13:26:29 -04:00
|
|
|
section.fields.map(field => {
|
2019-01-19 13:47:08 -05:00
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
switch (field.type) {
|
2019-05-27 11:39:16 -04:00
|
|
|
case 'uprn_list':
|
|
|
|
return <UPRNsDataEntry
|
2019-05-27 13:26:29 -04:00
|
|
|
key={field.slug}
|
|
|
|
title={field.title}
|
2019-05-27 11:39:16 -04:00
|
|
|
value={props.uprns}
|
2019-05-27 13:26:29 -04:00
|
|
|
tooltip={field.tooltip} />
|
2019-05-27 11:39:16 -04:00
|
|
|
case 'text_multi':
|
|
|
|
return <MultiDataEntry
|
2019-05-27 13:26:29 -04:00
|
|
|
key={field.slug}
|
|
|
|
title={field.title}
|
|
|
|
value={props[field.slug]}
|
|
|
|
tooltip={field.tooltip} />
|
2019-05-27 11:39:16 -04:00
|
|
|
case 'like':
|
|
|
|
return <LikeDataEntry
|
2019-05-27 13:26:29 -04:00
|
|
|
key={field.slug}
|
|
|
|
title={field.title}
|
|
|
|
value={props[field.slug]}
|
2019-05-27 11:39:16 -04:00
|
|
|
user_building_like={props.building_like}
|
2019-05-27 13:26:29 -04:00
|
|
|
tooltip={field.tooltip} />
|
2019-05-27 11:39:16 -04:00
|
|
|
default:
|
|
|
|
return <DataEntry
|
2019-05-27 13:26:29 -04:00
|
|
|
key={field.slug}
|
2019-05-27 15:13:43 -04:00
|
|
|
slug={field.slug}
|
2019-05-10 11:10:16 -04:00
|
|
|
cat={cat}
|
2019-05-27 13:26:29 -04:00
|
|
|
title={field.title}
|
|
|
|
value={props[field.slug]}
|
|
|
|
tooltip={field.tooltip} />
|
2019-01-19 13:47:08 -05:00
|
|
|
}
|
2018-10-25 09:36:52 -04:00
|
|
|
})
|
2018-10-03 16:47:49 -04:00
|
|
|
}
|
|
|
|
</DataSection>
|
|
|
|
))
|
|
|
|
}
|
|
|
|
</Sidebar>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
BuildingView.propTypes = {
|
|
|
|
building_id: PropTypes.string,
|
|
|
|
match: PropTypes.object,
|
|
|
|
uprns: PropTypes.arrayOf(PropTypes.shape({
|
|
|
|
uprn: PropTypes.string.isRequired,
|
|
|
|
parent_uprn: PropTypes.string
|
|
|
|
})),
|
|
|
|
building_like: PropTypes.bool
|
|
|
|
}
|
2018-10-03 16:47:49 -04:00
|
|
|
|
|
|
|
const DataSection = (props) => {
|
2018-11-29 17:00:53 -05:00
|
|
|
const match = props.cat === props.slug;
|
2018-09-30 19:32:24 -04:00
|
|
|
return (
|
2019-05-27 11:31:48 -04:00
|
|
|
<section id={props.slug} className={(props.inactive)? 'data-section inactive': 'data-section'}>
|
|
|
|
<header className={`section-header view ${props.slug} ${(match? 'active' : '')}`}>
|
2018-10-04 17:50:33 -04:00
|
|
|
<NavLink
|
2018-11-29 17:00:53 -05:00
|
|
|
to={`/view/${props.slug}/building/${props.building_id}.html`}
|
2018-10-25 05:47:19 -04:00
|
|
|
title={(props.inactive)? 'Coming soon… Click the ? for more info.' :
|
|
|
|
(match)? 'Hide details' : 'Show details'}
|
2018-10-04 17:50:33 -04:00
|
|
|
isActive={() => match}>
|
2018-10-01 11:59:39 -04:00
|
|
|
<h3 className="h3">{props.title}</h3>
|
|
|
|
</NavLink>
|
2018-10-05 04:10:20 -04:00
|
|
|
<nav className="icon-buttons">
|
2019-05-27 11:39:16 -04:00
|
|
|
{
|
|
|
|
props.help?
|
|
|
|
<a className="icon-button help" title="Find out more" href={props.help}>
|
2019-01-22 14:39:16 -05:00
|
|
|
Info
|
2019-05-27 11:39:16 -04:00
|
|
|
</a>
|
|
|
|
: null
|
|
|
|
}
|
|
|
|
{
|
|
|
|
!props.inactive?
|
|
|
|
<NavLink className="icon-button edit" title="Edit data"
|
|
|
|
to={`/edit/${props.slug}/building/${props.building_id}.html`}>
|
2018-10-25 06:48:25 -04:00
|
|
|
Edit
|
2019-05-27 11:39:16 -04:00
|
|
|
<EditIcon />
|
|
|
|
</NavLink>
|
|
|
|
: null
|
|
|
|
}
|
2018-10-05 04:10:20 -04:00
|
|
|
</nav>
|
2018-10-01 11:59:39 -04:00
|
|
|
</header>
|
2019-01-22 14:39:16 -05:00
|
|
|
{
|
|
|
|
match?
|
|
|
|
!props.inactive?
|
2019-05-27 11:39:16 -04:00
|
|
|
<dl className="data-list">{props.children}</dl>
|
|
|
|
: <p className="data-intro">{props.intro}</p>
|
|
|
|
: null
|
2019-01-22 14:39:16 -05:00
|
|
|
}
|
2018-09-30 19:32:24 -04:00
|
|
|
</section>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
DataSection.propTypes = {
|
|
|
|
title: PropTypes.string,
|
|
|
|
cat: PropTypes.string,
|
|
|
|
slug: PropTypes.string,
|
|
|
|
intro: PropTypes.string,
|
|
|
|
help: PropTypes.string,
|
|
|
|
inactive: PropTypes.bool,
|
|
|
|
building_id: PropTypes.string,
|
|
|
|
children: PropTypes.node
|
|
|
|
}
|
|
|
|
|
2018-10-03 16:47:49 -04:00
|
|
|
const DataEntry = (props) => (
|
|
|
|
<Fragment>
|
|
|
|
<dt>
|
|
|
|
{ props.title }
|
|
|
|
{ props.tooltip? <Tooltip text={ props.tooltip } /> : null }
|
2019-05-10 11:10:16 -04:00
|
|
|
{ (props.cat && props.slug && props.value)?
|
|
|
|
<div className="icon-buttons">
|
|
|
|
<NavLink
|
|
|
|
to={`/multi-edit/${props.cat}.html?k=${props.slug}&v=${props.value}`}
|
|
|
|
className="icon-button copy">
|
|
|
|
Copy
|
|
|
|
</NavLink>
|
|
|
|
</div> : null
|
|
|
|
}
|
2018-10-03 16:47:49 -04:00
|
|
|
</dt>
|
2019-01-22 12:56:28 -05:00
|
|
|
<dd>{
|
2019-05-27 11:31:48 -04:00
|
|
|
(props.value != null && props.value !== '')?
|
|
|
|
(typeof(props.value) === 'boolean')?
|
2019-01-22 12:56:28 -05:00
|
|
|
(props.value)? 'Yes' : 'No'
|
|
|
|
: props.value
|
|
|
|
: '\u00A0'}</dd>
|
2018-10-03 16:47:49 -04:00
|
|
|
</Fragment>
|
|
|
|
);
|
2018-09-09 17:22:44 -04:00
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
DataEntry.propTypes = {
|
|
|
|
title: PropTypes.string,
|
2019-05-27 15:13:43 -04:00
|
|
|
cat: PropTypes.string,
|
|
|
|
slug: PropTypes.string,
|
2019-05-27 13:26:29 -04:00
|
|
|
tooltip: PropTypes.string,
|
|
|
|
value: PropTypes.any
|
|
|
|
}
|
|
|
|
|
2019-01-22 12:21:44 -05:00
|
|
|
const LikeDataEntry = (props) => (
|
|
|
|
<Fragment>
|
|
|
|
<dt>
|
|
|
|
{ props.title }
|
|
|
|
{ props.tooltip? <Tooltip text={ props.tooltip } /> : null }
|
2019-05-10 11:10:16 -04:00
|
|
|
<div className="icon-buttons">
|
|
|
|
<NavLink
|
|
|
|
to={`/multi-edit/${props.cat}.html?k=like&v=${true}`}
|
|
|
|
className="icon-button copy">
|
|
|
|
Copy
|
|
|
|
</NavLink>
|
|
|
|
</div>
|
2019-01-22 12:21:44 -05:00
|
|
|
</dt>
|
|
|
|
<dd>
|
2019-05-27 11:39:16 -04:00
|
|
|
{
|
|
|
|
(props.value != null)?
|
|
|
|
(props.value === 1)?
|
|
|
|
`${props.value} person likes this building`
|
|
|
|
: `${props.value} people like this building`
|
|
|
|
: '\u00A0'
|
|
|
|
}
|
2019-01-22 12:21:44 -05:00
|
|
|
</dd>
|
|
|
|
{
|
|
|
|
(props.user_building_like)? <dd>…including you!</dd> : null
|
|
|
|
}
|
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
LikeDataEntry.propTypes = {
|
|
|
|
title: PropTypes.string,
|
2019-05-27 15:13:43 -04:00
|
|
|
cat: PropTypes.string,
|
2019-05-27 13:26:29 -04:00
|
|
|
tooltip: PropTypes.string,
|
|
|
|
value: PropTypes.any,
|
|
|
|
user_building_like: PropTypes.bool
|
|
|
|
}
|
|
|
|
|
2019-01-19 13:47:08 -05:00
|
|
|
const MultiDataEntry = (props) => {
|
|
|
|
let content;
|
|
|
|
|
|
|
|
if (props.value && props.value.length) {
|
|
|
|
content = <ul>{
|
|
|
|
props.value.map((item, index) => {
|
2019-05-27 13:26:29 -04:00
|
|
|
return <li key={index}><a href={sanitiseURL(item)}>{item}</a></li>
|
2019-01-19 13:47:08 -05:00
|
|
|
})
|
|
|
|
}</ul>
|
|
|
|
} else {
|
|
|
|
content = '\u00A0'
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Fragment>
|
|
|
|
<dt>
|
|
|
|
{ props.title }
|
|
|
|
{ props.tooltip? <Tooltip text={ props.tooltip } /> : null }
|
|
|
|
</dt>
|
|
|
|
<dd>{ content }</dd>
|
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
MultiDataEntry.propTypes = {
|
|
|
|
title: PropTypes.string,
|
|
|
|
tooltip: PropTypes.string,
|
|
|
|
value: PropTypes.arrayOf(PropTypes.string)
|
|
|
|
}
|
|
|
|
|
|
|
|
function sanitiseURL(string){
|
2019-01-19 13:47:08 -05:00
|
|
|
let url_
|
|
|
|
|
|
|
|
// http or https
|
|
|
|
if (!(string.substring(0, 7) === 'http://' || string.substring(0, 8) === 'https://')){
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
url_ = document.createElement('a')
|
|
|
|
url_.href = string
|
|
|
|
} catch (error) {
|
|
|
|
try {
|
|
|
|
url_ = urlapi.parse(string)
|
|
|
|
} catch (error) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// required (www.example.com)
|
|
|
|
if (!url_.hostname || url_.hostname === '' || url_.hostname === 'localhost'){
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
|
|
|
// optional (/some/path)
|
|
|
|
// url_.pathname;
|
|
|
|
|
|
|
|
// optional (?name=value)
|
|
|
|
// url_.search;
|
|
|
|
|
|
|
|
// optional (#anchor)
|
|
|
|
// url_.hash;
|
|
|
|
|
|
|
|
return `${url_.protocol}//${url_.hostname}${url_.pathname || ''}${url_.search || ''}${url_.hash || ''}`
|
|
|
|
}
|
|
|
|
|
2018-10-25 09:36:52 -04:00
|
|
|
const UPRNsDataEntry = (props) => {
|
|
|
|
const uprns = props.value || [];
|
2019-05-27 13:26:29 -04:00
|
|
|
const noParent = uprns.filter(uprn => uprn.parent_uprn == null);
|
|
|
|
const withParent = uprns.filter(uprn => uprn.parent_uprn != null);
|
2018-10-25 09:36:52 -04:00
|
|
|
|
|
|
|
return (
|
2019-05-27 11:39:16 -04:00
|
|
|
<Fragment>
|
|
|
|
<dt>
|
|
|
|
{ props.title }
|
|
|
|
{ props.tooltip? <Tooltip text={ props.tooltip } /> : null }
|
|
|
|
</dt>
|
|
|
|
<dd><ul className="uprn-list">
|
|
|
|
<Fragment>{
|
2019-05-27 13:26:29 -04:00
|
|
|
noParent.length?
|
|
|
|
noParent.map(uprn => (
|
2019-05-27 11:39:16 -04:00
|
|
|
<li key={uprn.uprn}>{uprn.uprn}</li>
|
2018-10-25 09:36:52 -04:00
|
|
|
))
|
2019-05-27 11:39:16 -04:00
|
|
|
: '\u00A0'
|
|
|
|
}</Fragment>
|
|
|
|
{
|
2019-05-27 13:26:29 -04:00
|
|
|
withParent.length?
|
2019-05-27 11:39:16 -04:00
|
|
|
<details>
|
|
|
|
<summary>Children</summary>
|
|
|
|
{
|
2019-05-27 13:26:29 -04:00
|
|
|
withParent.map(uprn => (
|
2019-05-27 11:39:16 -04:00
|
|
|
<li key={uprn.uprn}>{uprn.uprn} (child of {uprn.parent_uprn})</li>
|
|
|
|
))
|
|
|
|
}
|
|
|
|
</details>
|
|
|
|
: null
|
|
|
|
}
|
|
|
|
</ul></dd>
|
|
|
|
</Fragment>
|
2018-10-25 09:36:52 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
UPRNsDataEntry.propTypes = {
|
|
|
|
title: PropTypes.string,
|
|
|
|
tooltip: PropTypes.string,
|
|
|
|
value: PropTypes.arrayOf(PropTypes.shape({
|
|
|
|
uprn: PropTypes.string.isRequired,
|
|
|
|
parent_uprn: PropTypes.string
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2018-09-09 17:22:44 -04:00
|
|
|
export default BuildingView;
|