diff --git a/plugins/data-fetch/fetchEvictorData.ts b/plugins/data-fetch/fetchEvictorData.ts index eb9ae46..534dfe3 100644 --- a/plugins/data-fetch/fetchEvictorData.ts +++ b/plugins/data-fetch/fetchEvictorData.ts @@ -2,6 +2,7 @@ import "dotenv/config" import { createClient } from "contentful" import type { EntryCollection } from "contentful" import getEBEntry from "./getEBEntry" +import { formatLink } from "../../src/utils/string" export default async function fetchEvictorData() { const client = createClient({ @@ -25,6 +26,8 @@ export default async function fetchEvictorData() { const { ebEntry, name, pullQuote, citywideListDescription } = item.fields + const evictorNameFormatted = formatLink(name) // created formatted version of name + if (!ebEntry?.length) { console.warn( `${name} doesn't have an Evictorbook entry entered on Contentful` @@ -93,9 +96,8 @@ export default async function fetchEvictorData() { await ebData.reduce( async (shells: Promise, business) => { const networkId = business.networkDetails[0].network_id - const networkUrl = `${ - process.env.EB_DOMAIN || "https://evictorbook.com" - }/api/network/${networkId}/nodes` + const networkUrl = `${process.env.EB_DOMAIN || "https://evictorbook.com" + }/api/network/${networkId}/nodes` const nodes = await fetch(networkUrl).then((res) => res.json() ) @@ -131,6 +133,7 @@ export default async function fetchEvictorData() { ...item.fields, id: item.sys.id, ebData, + nameFormatted: evictorNameFormatted, // add in formatted name as queryable field totalEvictions, activeSince, totalUnits, diff --git a/src/components/Evictor.tsx b/src/components/Evictor.tsx index 185bb39..5af4602 100644 --- a/src/components/Evictor.tsx +++ b/src/components/Evictor.tsx @@ -1,25 +1,28 @@ import React from 'react' import renderContent from '../utils/contentful-render' -import {OutboundLink} from './OutboundLink' -import type {EvictorProps} from '../queries/list' -import {getImage} from 'gatsby-plugin-image' +import { OutboundLink } from './OutboundLink' +import type { EvictorProps } from '../queries/list' +import { getImage } from 'gatsby-plugin-image' import { FormatBusinessAddress, titleCase, } from '../utils/string' import EvictorImage from './EvictorImage' import pin from '../images/pin.svg' -import {formatLink} from '../utils/string' +import { formatLink } from '../utils/string' import '../styles/list.scss' const EvictorProfile: React.FC<{ content: EvictorProps city: string -}> = ({content, city}) => { - const {networkDetails, details} = content.ebData[0] +}> = ({ content, city }) => { + const { networkDetails, details } = content.ebData[0] const activeSince = content.activeSince + const formatter = new Intl.DateTimeFormat('en-US', { dateStyle: 'medium' }) + const dateLastUpdated = formatter.format(new Date(content.lastUpdated)) + return (
+ {content.aempUrl && ( + + See AEMP's original profile on this landlord + + )} {content.banks?.length ? (

Funded By @@ -120,6 +131,10 @@ const EvictorProfile: React.FC<{ 's portfolio ))} + {content.lastUpdated && ( + Profile last updated on {dateLastUpdated} + + )} )} diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index e771b24..e1ea3e9 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -49,7 +49,7 @@ const Layout = ({ - + @@ -58,7 +58,7 @@ const Layout = ({ - + { + // pull the evictor ID populated through Gatsby's "collection route" setup for dynamic pages + // See more here: https://www.gatsbyjs.com/docs/reference/routing/file-system-route-api + const evictorId = props.pageContext.id + + const data = useListQuery() // pull the full list of evictors + const evictors = sortEvictors( + data.allEvictor.nodes + ) as EvictorProps[] + + /* Because static GraphQL queries don't allow for variables / dynamic searches, easiest to + * pull the full list of evictors and then filter here to the evictor for this page. + * + * TODO - if this becomes a performance issue, can restructure around a dynamic query + */ + + const evictorToDisplay = evictors.filter((evictor) => evictor.id == evictorId)[0] + const evictorCity = evictorToDisplay.city == "sf" ? 'San Francisco' : 'Oakland' + + return ( + +

+
+
+
+ +
+ + ) +} + +export default SingleEvictorPage diff --git a/src/queries/list.ts b/src/queries/list.ts index 614089f..a3a25b3 100644 --- a/src/queries/list.ts +++ b/src/queries/list.ts @@ -1,7 +1,7 @@ -import {useStaticQuery, graphql} from 'gatsby' -import {ImageDataLike} from 'gatsby-plugin-image' +import { useStaticQuery, graphql } from 'gatsby' +import { ImageDataLike } from 'gatsby-plugin-image' -export default function useIndexQuery() { +export default function useListQuery() { const data = useStaticQuery(graphql` query { contentfulCitywideListPage { @@ -9,13 +9,17 @@ export default function useIndexQuery() { } allEvictor { nodes { + id name + nameFormatted city nonprofitOrLowIncome corporation photoCaption shellCompanies tags + lastUpdated + aempUrl evictions { type evict_date @@ -62,10 +66,14 @@ export default function useIndexQuery() { /** might as well define some proptypes */ export type EvictorProps = { + id: number name: string + nameFormatted: string corporation: string city: string tags?: string[] + lastUpdated?: string + aempUrl?: string evictions: { type: string evict_date: string diff --git a/src/styles/list.scss b/src/styles/list.scss index 541a75c..0360b9f 100644 --- a/src/styles/list.scss +++ b/src/styles/list.scss @@ -14,6 +14,7 @@ display: grid; grid-template-rows: 1fr auto; max-height: 100vh; + @media (min-width: 700px) { .scroll-container { overflow-y: scroll; @@ -28,28 +29,35 @@ border-bottom: solid 1px white; z-index: 1; width: 100%; + h1 { font-size: 1.5rem !important; margin: 0 !important; margin-right: 0.5rem !important; } + .header { width: 100%; padding: 0.5rem; + .title-container { margin: 0 !important; } + .title { place-items: center; margin: 0 !important; + h1 { text-align: center; } + img { height: 1.5rem; } } } + .title-links { width: 100%; display: flex; @@ -57,6 +65,7 @@ justify-content: space-around; flex-wrap: wrap; } + .links { place-items: center; place-content: center; @@ -74,25 +83,32 @@ and .link-target has position: absolute; */ position: relative; + .spacer { height: 10rem; } + .city-name { display: flex; flex-direction: row; align-items: center; gap: 1rem; + img { height: 1.5rem; } + span { font-size: 1.5rem; margin: 0; } + margin: 1rem 0; } + .tags { margin: 1rem 0; + .tag { font-style: italic; font-size: 1.5rem; @@ -100,12 +116,19 @@ } } +.date_updated { + margin: 2rem 0; + font-style: italic; + font-size: 1rem; +} + .col-container { min-height: 100vh; display: flex; flex-direction: row; flex-wrap: wrap; justify-content: space-around; + .left, .right { flex: 1 1 50ch; @@ -116,6 +139,7 @@ flex-direction: column; place-items: center; margin: 0 1.5rem; + .left-width-constrainer, .right-width-constrainer { width: 100%; @@ -139,8 +163,8 @@ font-weight: bold; text-transform: uppercase; } + li { margin-left: 1rem; } -} - +} \ No newline at end of file