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

Pre-details wrapup #145

Merged
merged 10 commits into from
Dec 8, 2020
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ and ArcGIS.

#### Mapbox lookup tables

**DEPRECATED: no longer using Boundaries for census, custom tileset instead**.
Removed after `b9086b0`.

Whittled down MB lookup tables for `boundaries-sta4-v3-US`. Combination of CSV,
GeoJSON, spreadsheets to make formulas for creating lat/lng for QGIS temporary
use. Resulting schema:
Expand Down
2,170 changes: 0 additions & 2,170 deletions public/data/lookup-tables/sta4-v3-new-york.json

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/config/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ const CONFIG_WORKBOOK_ID = '1Ts7CvmlKVqCZs_AJ3hf5x1my2p-vaX7q5HxaXiduiEc'

export const GOOGLE_API_KEY = process.env.REACT_APP_GOOGLE_API_KEY
export const GOOGLE_API_BASE = `https://sheets.googleapis.com/v4/spreadsheets`
export const BASE_ENDPOINT = `${GOOGLE_API_BASE}/${CONFIG_WORKBOOK_ID}/values`
export const CONFIG_ENDPOINT = `${GOOGLE_API_BASE}/${CONFIG_WORKBOOK_ID}/values`
export const CONFIG_QUERY_ID = 'sheets-config'
21 changes: 13 additions & 8 deletions src/components/context/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,19 +114,24 @@ export type MapToolsAction =
}

export type MapToolsDispatch = React.Dispatch<MapToolsAction>
export type LangConfig = Pick<

// NOTE: it's not actually ALL the cols, but most
export type LangConfig = Omit<
LangRecordSchema,
| 'Language'
| 'Endonym'
| 'Global Speaker Total'
| 'Language Family'
| 'ISO 639-3'
| 'Glottocode'
| 'Description'
| 'County'
| 'ID'
| 'Latitude'
| 'Longitude'
| 'Macrocommunity'
| 'Neighborhood'
| 'Size'
| 'Status'
| 'Town'
> & {
'PUMA Field'?: string
'Tract Field'?: string
'Census Pretty'?: string // MATCH/INDEX convenience lookup
'Global Speaker Total'?: string // MB has int, Google API string
Font?: string
}

Expand Down
12 changes: 7 additions & 5 deletions src/components/details/Chips.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,20 @@ const useStyles = makeStyles((theme: Theme) =>
cursor: 'pointer',
display: 'inline-flex',
lineHeight: 1.5,
marginBottom: '0.25em', // otherwise crowded when wrapped
padding: '0.15em 0.45em',
marginBottom: '0.25rem', // otherwise crowded when wrapped
padding: '0.1rem 0.35rem',
transition: '300ms backgroundColor ease',
whiteSpace: 'nowrap',
fontSize: '0.7rem',
'&:hover': {
backgroundColor: theme.palette.grey[800],
},
'& > :first-child': {
marginRight: '0.35em',
'& img, svg': {
marginRight: '0.35rem',
},
'& > svg': {
fontSize: '1.25em',
fontSize: '0.8rem',
marginRight: '0.25rem',
},
'& .country-flag': {
// Ensure outer white shapes are seen
Expand Down
96 changes: 12 additions & 84 deletions src/components/details/DetailsPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,108 +1,36 @@
import React, { FC, useContext } from 'react'
import { Link as RouterLink, useRouteMatch } from 'react-router-dom'
import { Typography, Divider, Button } from '@material-ui/core'
import { FaRandom } from 'react-icons/fa'
import { BiMapPin } from 'react-icons/bi'
import React, { FC } from 'react'
import { useRouteMatch } from 'react-router-dom'
import { Typography, Divider } from '@material-ui/core'

import { GlobalContext } from 'components/context'
import { RecordDescription } from 'components/results'
import { paths as routes } from 'components/config/routes'
import { useLangFeatByKeyVal } from 'components/map/hooks'
import { Media } from 'components/media'
import { MoreLikeThis } from 'components/details'
import { usePanelRootStyles } from 'components/panels/PanelContent'
import { LangOrEndoIntro } from './LangOrEndoIntro'
import { NeighborhoodList } from './NeighborhoodList'
import { NoFeatSel } from './NoFeatSel'
import { useStyles } from './styles'
import { findFeatureByID } from '../../utils'

type NeighborhoodList = {
town: string
neighborhoods: string
}

// TODO: separate files
const RandomLinkBtn: FC = () => {
const { state } = useContext(GlobalContext)
const { langFeatures } = state

if (!langFeatures.length) return null

const randoIndex = Math.floor(Math.random() * (langFeatures.length - 1))
const id = langFeatures[randoIndex].ID

return (
<Button
variant="contained"
color="primary"
component={RouterLink}
size="small"
startIcon={<FaRandom />}
to={`${routes.details}/${id}`}
>
Try one at random
</Button>
)
}

const NoFeatSel: FC<{ reason?: string }> = (props) => {
const { reason = 'No community selected.' } = props
const classes = useStyles()

return (
<div style={{ textAlign: 'center', maxWidth: '85%', margin: '16px auto' }}>
<Typography className={classes.noFeatSel}>
{reason} Click a community in the map or in the data table.
</Typography>
<RandomLinkBtn />
</div>
)
}

const NeighborhoodList: FC<NeighborhoodList> = (props) => {
const { town, neighborhoods } = props
const classes = useStyles()

return (
<Typography className={classes.neighborhoods}>
<BiMapPin />
{neighborhoods &&
neighborhoods.split(', ').map((place, i) => (
<React.Fragment key={place}>
{i !== 0 && <span className={classes.separator}>|</span>}
<RouterLink to={`/Explore/Neighborhood/${place}`}>
{place}
</RouterLink>
</React.Fragment>
))}
{/* At least for now, not linking to Towns */}
{!neighborhoods && town}
</Typography>
)
}

export const DetailsPanel: FC = () => {
const { state } = useContext(GlobalContext)
const classes = useStyles()
const panelRootClasses = usePanelRootStyles()
const match: { params: { id: string } } | null = useRouteMatch('/:any/:id')
const matchedFeatID = match?.params?.id

if (!matchedFeatID) return <NoFeatSel />
const { feature, stateReady } = useLangFeatByKeyVal(matchedFeatID, true)

// TODO: use MB's loading events to set this instead
if (!state.langFeatures.length)
if (!stateReady)
return (
<div className={`${panelRootClasses.root} ${classes.root}`}>
<p>Loading communities...</p>
</div>
)

const matchingRecord = findFeatureByID(
state.langFeatures,
parseInt(matchedFeatID, 10)
)
if (!matchedFeatID) return <NoFeatSel />

// TODO: send stuff to Sentry
if (!matchingRecord)
if (!feature)
return (
<div className={`${panelRootClasses.root} ${classes.root}`}>
<NoFeatSel
Expand All @@ -123,7 +51,7 @@ export const DetailsPanel: FC = () => {
Macrocommunity: macro,
'World Region': WorldRegion,
// Size, // TODO: cell strength bars for Size
} = matchingRecord
} = feature

document.title = `${language} - NYC Languages`

Expand All @@ -132,7 +60,7 @@ export const DetailsPanel: FC = () => {
{/* TODO: something that works */}
{/* {state.panelState === 'default' && ( <ScrollToTopOnMount elemID={elemID} trigger={loc.pathname} /> )} */}
<div className={`${panelRootClasses.root} ${classes.root}`} id={elemID}>
<LangOrEndoIntro attribs={matchingRecord} />
<LangOrEndoIntro attribs={feature} />
<NeighborhoodList neighborhoods={Neighborhood} town={Town} />
<MoreLikeThis
macro={macro}
Expand Down
50 changes: 27 additions & 23 deletions src/components/details/MoreLikeThis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ const useStyles = makeStyles((theme: Theme) =>
fontSize: '0.75rem',
justifyContent: 'center',
flexWrap: 'wrap',
marginBottom: '0.5em',
margin: '0.5rem 0 0',
'& > * + *': {
marginLeft: '0.5em',
marginLeft: '0.35rem',
},
},
})
)

export const MoreLikeThis: FC<Types.MoreLikeThisProps> = (props) => {
const { language, region, country, macro } = props
const { children, language, region, country, macro } = props
const symbLabelState = useSymbAndLabelState()
const classes = useStyles()
const regionSwatchColor =
Expand All @@ -38,35 +38,39 @@ export const MoreLikeThis: FC<Types.MoreLikeThisProps> = (props) => {
// Careful, not using TS on the mid-route paths, e.g. "World Region"
return (
<div className={classes.root}>
<SeeRelatedChip
name={language}
to={`${routes.grid}/Language/${language}`}
>
<BiUserVoice /> {language}
</SeeRelatedChip>
{country.split(', ').map((countryName) => (
{children}
{language && (
<SeeRelatedChip
key={countryName}
name={countryName}
to={`${routes.grid}/Country/${countryName}`}
name={language}
to={`${routes.grid}/Language/${language}`}
>
<img
className="country-flag"
alt={`${countryName} flag`}
src={`/img/country-flags/${getCodeByCountry(
countryName
).toLowerCase()}.svg`}
/>{' '}
{countryName}
<BiUserVoice /> {language}
</SeeRelatedChip>
))}
)}
{country &&
country.split(', ').map((countryName) => (
<SeeRelatedChip
key={countryName}
name={countryName}
to={`${routes.grid}/Country/${countryName}`}
>
<img
className="country-flag"
alt={`${countryName} flag`}
src={`/img/country-flags/${getCodeByCountry(
countryName
).toLowerCase()}.svg`}
/>{' '}
{countryName}
</SeeRelatedChip>
))}
<SeeRelatedChip
name={region}
to={`${routes.grid}/World Region/${region}`}
>
<LegendSwatch
legendLabel={region}
labelStyleOverride={{ fontSize: 'inherit' }}
labelStyleOverride={{ fontSize: '0.7rem' }}
component="div"
iconID="_circle"
backgroundColor={regionSwatchColor || 'transparent'}
Expand Down
29 changes: 29 additions & 0 deletions src/components/details/NeighborhoodList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React, { FC } from 'react'
import { Link as RouterLink } from 'react-router-dom'
import { Typography } from '@material-ui/core'
import { BiMapPin } from 'react-icons/bi'

import { useStyles } from './styles'
import * as Types from './types'

export const NeighborhoodList: FC<Types.NeighborhoodList> = (props) => {
const { town, neighborhoods } = props
const classes = useStyles()

return (
<Typography className={classes.neighborhoods}>
<BiMapPin />
{neighborhoods &&
neighborhoods.split(', ').map((place, i) => (
<React.Fragment key={place}>
{i !== 0 && <span className={classes.separator}>|</span>}
<RouterLink to={`/Explore/Neighborhood/${place}`}>
{place}
</RouterLink>
</React.Fragment>
))}
{/* At least for now, not linking to Towns */}
{!neighborhoods && town}
</Typography>
)
}
45 changes: 45 additions & 0 deletions src/components/details/NoFeatSel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React, { FC, useContext } from 'react'
import { Link as RouterLink } from 'react-router-dom'
import { Typography, Button } from '@material-ui/core'
import { FaRandom } from 'react-icons/fa'

import { GlobalContext } from 'components/context'
import { paths as routes } from 'components/config/routes'
import { useStyles } from './styles'

const RandomLinkBtn: FC = () => {
const { state } = useContext(GlobalContext)
const { langFeatures } = state

if (!langFeatures.length) return null

const randoIndex = Math.floor(Math.random() * (langFeatures.length - 1))
const id = langFeatures[randoIndex].ID

return (
<Button
variant="contained"
color="primary"
component={RouterLink}
size="small"
startIcon={<FaRandom />}
to={`${routes.details}/${id}`}
>
Try one at random
</Button>
)
}

export const NoFeatSel: FC<{ reason?: string }> = (props) => {
const { reason = 'No community selected.' } = props
const classes = useStyles()

return (
<div style={{ textAlign: 'center', maxWidth: '85%', margin: '16px auto' }}>
<Typography className={classes.noFeatSel}>
{reason} Click a community in the map or in the data table.
</Typography>
<RandomLinkBtn />
</div>
)
}
7 changes: 6 additions & 1 deletion src/components/details/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export type MoreLikeThisProps = {
language: string
region: string
country: string
language?: string
macro?: string
}

Expand All @@ -17,3 +17,8 @@ export type ChipWithClickProps = {
icon?: React.ReactNode
handleClick: (e: React.MouseEvent<HTMLDivElement>) => void
}

export type NeighborhoodList = {
town: string
neighborhoods: string
}
Loading