From af41f2fac44b15da27d3b41db8f99c4a5f192ead Mon Sep 17 00:00:00 2001 From: Elvira Date: Wed, 20 Mar 2024 14:47:10 +0100 Subject: [PATCH 01/65] add new components for regional and company views --- __tests__/components/CompanyView.tsx | 92 +++++++++++++ __tests__/components/PillSwitch.tsx | 83 ++++++++++++ __tests__/components/RegionalView.tsx | 180 ++++++++++++++++++++++++++ dummy_companies.json | 112 ++++++++++++++++ utils/types.ts | 1 - 5 files changed, 467 insertions(+), 1 deletion(-) create mode 100644 __tests__/components/CompanyView.tsx create mode 100644 __tests__/components/PillSwitch.tsx create mode 100644 __tests__/components/RegionalView.tsx create mode 100644 dummy_companies.json diff --git a/__tests__/components/CompanyView.tsx b/__tests__/components/CompanyView.tsx new file mode 100644 index 00000000..5745b213 --- /dev/null +++ b/__tests__/components/CompanyView.tsx @@ -0,0 +1,92 @@ +import styled from 'styled-components' +import { H2Regular, H5Regular, Paragraph } from './Typography' +import { devices } from '../utils/devices' +import { Company } from '../utils/types' +import ComparisonTable from './ComparisonTable' +import { companyColumns } from '../utils/createCompanyList' +import ToggleButton from './ToggleButton' +import { defaultDataView, secondaryDataView } from '../utils/datasetDescriptions' +import ListIcon from '../public/icons/list.svg' +import MapIcon from '../public/icons/map.svg' + +const InfoText = styled.div` + padding: 0 16px; +` + +const ParagraphSource = styled(Paragraph)` + font-size: 13px; + color: ${({ theme }) => theme.grey}; +` + +const InfoContainer = styled.div` + width: 100%; + position: relative; + background: ${({ theme }) => theme.lightBlack}; + border-radius: 8px; + margin-bottom: 32px; + z-index: 15; + ::-webkit-scrollbar { + display: none; + } +` + +const TitleContainer = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 64px; +` + +const FloatingH5 = styled(H5Regular)` + position: absolute; + margin: 60px 0 0 16px; + z-index: 200; + + @media only screen and (${devices.mobile}) { + margin: 55px 0 0 16px; + } +` + +type CompanyViewProps = { + companies: Array + selectedDataView: string + setSelectedDataView: (newData: string) => void +} + +function CompanyView({ + companies, + selectedDataView, + setSelectedDataView, +}: CompanyViewProps) { + const cols = companyColumns() + + const handleToggleView = () => { + const newDataView = selectedDataView === defaultDataView ? secondaryDataView : defaultDataView + setSelectedDataView(newDataView) + } + + const isDefaultDataView = selectedDataView === defaultDataView + + return ( + <> + Hur går det med företagen? + + + Företagens utsläpp + + : } + /> + + + Lorem + Lorem ipsum + + + + ) +} + +export default CompanyView diff --git a/__tests__/components/PillSwitch.tsx b/__tests__/components/PillSwitch.tsx new file mode 100644 index 00000000..91c0b83a --- /dev/null +++ b/__tests__/components/PillSwitch.tsx @@ -0,0 +1,83 @@ +import React, { useState } from 'react' +import styled from 'styled-components' + +const SwitchLabel = styled.label` + position: relative; + display: flex; + align-items: center; + justify-content: space-between; + width: 240px; + height: 56px; + background: ${({ theme }) => theme.lightGreen}; + border-radius: 28px; + margin-bottom: 40px; + cursor: pointer; +` + +const Slider = styled.div<{ isActive: boolean }>` + position: absolute; + top: 4px; + left: ${({ isActive }) => (isActive ? 'calc(100% - 122px)' : '4px')}; /* Width of the switch - width of slider */ + width: 120px; /* Width of the slider */ + height: 48px; /* Height of the slider */ + background: #fff; + border-radius: 48px; /* Half of the height to make it pill-shaped */ + transition: 0.2s; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; + font-weight: bold; + z-index: 1; +` + +const SwitchInput = styled.input` + opacity: 0; + width: 0; + height: 0; +` + +const TextLeft = styled.span` + position: absolute; + left: 16px; + color: black; + pointer-events: none; /* ignore pointer events so label still triggers input */ + z-index: 10; +` + +const TextRight = styled.span` + position: absolute; + right: 16px; + color: black; + pointer-events: none; + z-index: 10; +` + +type PillSwitchProps = { + onToggle: (isActive: boolean) => void +} + +function PillSwitch({ onToggle }: PillSwitchProps) { + const [isActive, setIsActive] = useState(true) + + const handleToggle = () => { + const newIsActive = !isActive + setIsActive(newIsActive) + onToggle(newIsActive) + } + + return ( + + Företag + Geografiskt + + + + ) +} + +export default PillSwitch diff --git a/__tests__/components/RegionalView.tsx b/__tests__/components/RegionalView.tsx new file mode 100644 index 00000000..3d71740a --- /dev/null +++ b/__tests__/components/RegionalView.tsx @@ -0,0 +1,180 @@ +import dynamic from 'next/dynamic' +import styled from 'styled-components' +import { NextRouter } from 'next/router' +import ComparisonTable from '../components/ComparisonTable' +import MapLabels from '../components/Map/MapLabels' +import ListIcon from '../public/icons/list.svg' +import MapIcon from '../public/icons/map.svg' +import ToggleButton from '../components/ToggleButton' +import RadioButtonMenu from './RadioButtonMenu' +import DropDown from '../components/DropDown' +import { H2Regular, H5Regular, Paragraph } from './Typography' +import { devices } from '../utils/devices' +import { + datasetDescriptions, + currentData, + defaultDataView, + secondaryDataView, +} from '../utils/datasetDescriptions' +import { Municipality, SelectedData } from '../utils/types' +import { normalizeString } from '../utils/shared' +import { municipalityColumns, rankData } from '../utils/createMunicipalityList' + +const Map = dynamic(() => import('../components/Map/Map')) + +const InfoText = styled.div` + padding: 0 16px; +` + +const ParagraphSource = styled(Paragraph)` + font-size: 13px; + color: ${({ theme }) => theme.grey}; +` + +const InfoContainer = styled.div` + width: 100%; + position: relative; + background: ${({ theme }) => theme.lightBlack}; + border-radius: 8px; + margin-bottom: 32px; + z-index: 15; + ::-webkit-scrollbar { + display: none; + } +` + +const TitleContainer = styled.div` + display: flex; + justify-content: space-between; + align-items: center; +` + +const FloatingH5 = styled(H5Regular)` + position: absolute; + margin: 60px 0 0 16px; + z-index: 200; + + @media only screen and (${devices.mobile}) { + margin: 55px 0 0 16px; + } +` + +const ComparisonContainer = styled.div<{ $dataView: string }>` + position: relative; + overflow-y: scroll; + z-index: 100; + // TODO: Hardcoding this is not good. + height: 400px; + border-radius: 8px; + display: flex; + margin-top: ${({ $dataView }) => ($dataView === secondaryDataView ? '64px' : '0')}; + + @media only screen and (${devices.tablet}) { + height: 500px; + } + + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + ::-webkit-scrollbar { + /* Chrome, Safari and Opera */ + display: none; + } +` + +type RegionalViewProps = { + municipalities: Array + selectedDataset: SelectedData + setSelectedDataset: (newData: SelectedData) => void + selectedDataView: string + setSelectedDataView: (newData: string) => void + router: NextRouter +} + +function RegionalView({ + municipalities, + selectedDataset, + setSelectedDataset, + selectedDataView, + setSelectedDataView, + router, +}: RegionalViewProps) { + const handleDataChange = (newData: SelectedData) => { + const newDataString = newData as string + setSelectedDataset(newDataString) + const normalizedDataset = normalizeString(newDataString) + router.push(`/${normalizedDataset}/${selectedDataView}`, undefined, { + shallow: true, + scroll: false, + }) + } + + const municipalityNames = municipalities.map((item) => item.Name) // get all municipality names for drop down + const municipalityData = currentData(municipalities, selectedDataset) // get all municipality names and data points for map and list + const datasetDescription = datasetDescriptions[selectedDataset] // get description of selected dataset + + const handleToggleView = () => { + const newDataView = selectedDataView === defaultDataView ? secondaryDataView : defaultDataView + setSelectedDataView(newDataView) + router.replace( + `/${normalizeString(selectedDataset as string)}/${newDataView}`, + undefined, + { + shallow: true, + scroll: false, + }, + ) + } + + const cols = municipalityColumns(selectedDataset, datasetDescription) + const rankedData = rankData(municipalities, selectedDataset) + + const isDefaultDataView = selectedDataView === defaultDataView + + return ( + <> + Hur går det med? + + + + {datasetDescription.title} + : } + /> + + + {isDefaultDataView && ( + <> + + + + )} + {selectedDataView === secondaryDataView && ( + + )} + + + {datasetDescription.body} + {datasetDescription.source} + + + + + ) +} + +export default RegionalView diff --git a/dummy_companies.json b/dummy_companies.json new file mode 100644 index 00000000..9c58c538 --- /dev/null +++ b/dummy_companies.json @@ -0,0 +1,112 @@ +[ + { + "name": "Example Company", + "industry": "Manufacturing", + "baseYear": "2019", + "url": "https://example.com", + "scope1": "1236", + "scope2": "1235", + "scope3": "5322000", + "totalEmissions": "1555", + "totalUnit": "Million ton CO2e" + }, + { + "name": "Example Company 2", + "industry": "Manufacturing", + "baseYear": "2019", + "url": "https://example2.com", + "scope1": "1234", + "scope2": "1235", + "scope3": "5322000", + "totalEmissions": "1553", + "totalUnit": "Million ton CO2e" + }, + { + "name": "Example Company 3", + "industry": "Technology", + "baseYear": "2018", + "url": "https://example3.com", + "scope1": "1365", + "scope2": "1563", + "scope3": "5200000", + "totalEmissions": "1500", + "totalUnit": "Million ton CO2e" + }, + { + "name": "Example Company 4", + "industry": "Energy", + "baseYear": "2017", + "url": "https://example4.com", + "scope1": "1400", + "scope2": "1300", + "scope3": "5000000", + "totalEmissions": "1450", + "totalUnit": "Million ton CO2e" + }, + { + "name": "Example Company 5", + "industry": "Automotive", + "baseYear": "2019", + "url": "https://example5.com", + "scope1": "1500", + "scope2": "1350", + "scope3": "5500000", + "totalEmissions": "1600", + "totalUnit": "Million ton CO2e" + }, + { + "name": "Example Company 6", + "industry": "Agriculture", + "baseYear": "2016", + "url": "https://example6.com", + "scope1": "1150", + "scope2": "1250", + "scope3": "5100000", + "totalEmissions": "1400", + "totalUnit": "Million ton CO2e" + }, + { + "name": "Example Company 7", + "industry": "Retail", + "baseYear": "2019", + "url": "https://example7.com", + "scope1": "1100", + "scope2": "1300", + "scope3": "5150000", + "totalEmissions": "1425", + "totalUnit": "Million ton CO2e" + }, + { + "name": "Example Company 8", + "industry": "Finance", + "baseYear": "2019", + "url": "https://example8.com", + "scope1": "1200", + "scope2": "1400", + "scope3": "5300000", + "totalEmissions": "1550", + "totalUnit": "Million ton CO2e" + }, + { + "name": "Example Company 9", + "industry": "Construction", + "baseYear": "2018", + "url": "https://example9.com", + "scope1": "1300", + "scope2": "1250", + "scope3": "5400000", + "totalEmissions": "1505", + "totalUnit": "Million ton CO2e" + }, + { + "name": "Example Company 10", + "industry": "Real Estate", + "baseYear": "2017", + "url": "https://example10.com", + "scope1": "1340", + "scope2": "1390", + "scope3": "5501000", + "totalEmissions": "1600", + "totalUnit": "Million ton CO2e" + } +] \ No newline at end of file diff --git a/utils/types.ts b/utils/types.ts index 61270362..36fb7791 100644 --- a/utils/types.ts +++ b/utils/types.ts @@ -31,7 +31,6 @@ export type ApproximatedEmission = { export type Budget = { CO2Equivalent: number - PercentageOfNationalBudget: number BudgetPerYear: Array } From 4c01da8ad89d3d5c6543311040a090c6de8acde0 Mon Sep 17 00:00:00 2001 From: Elvira Date: Wed, 20 Mar 2024 15:02:40 +0100 Subject: [PATCH 02/65] add company data service and dito create list --- __tests__/index.test.tsx | 1 - .../components => components}/CompanyView.tsx | 0 .../components => components}/PillSwitch.tsx | 0 .../RegionalView.tsx | 2 +- pages/[dataset]/[dataView]/index.tsx | 22 ++- pages/index.tsx | 175 +++--------------- utils/climateDataService.tsx | 26 ++- utils/companyDataService.tsx | 50 +++++ utils/createCompanyList.tsx | 21 +++ utils/createMunicipalityList.tsx | 2 +- utils/types.ts | 28 +++ 11 files changed, 156 insertions(+), 171 deletions(-) rename {__tests__/components => components}/CompanyView.tsx (100%) rename {__tests__/components => components}/PillSwitch.tsx (100%) rename {__tests__/components => components}/RegionalView.tsx (99%) create mode 100644 utils/companyDataService.tsx create mode 100644 utils/createCompanyList.tsx diff --git a/__tests__/index.test.tsx b/__tests__/index.test.tsx index 1a0f15bd..c7dbdc87 100644 --- a/__tests__/index.test.tsx +++ b/__tests__/index.test.tsx @@ -33,7 +33,6 @@ describe('Home Page', () => { Budget: { BudgetPerYear: [], CO2Equivalent: 0, - PercentageOfNationalBudget: 0, }, PoliticalRule: [], EmissionTrend: { diff --git a/__tests__/components/CompanyView.tsx b/components/CompanyView.tsx similarity index 100% rename from __tests__/components/CompanyView.tsx rename to components/CompanyView.tsx diff --git a/__tests__/components/PillSwitch.tsx b/components/PillSwitch.tsx similarity index 100% rename from __tests__/components/PillSwitch.tsx rename to components/PillSwitch.tsx diff --git a/__tests__/components/RegionalView.tsx b/components/RegionalView.tsx similarity index 99% rename from __tests__/components/RegionalView.tsx rename to components/RegionalView.tsx index 3d71740a..24f231b5 100644 --- a/__tests__/components/RegionalView.tsx +++ b/components/RegionalView.tsx @@ -125,7 +125,7 @@ function RegionalView({ ) } - const cols = municipalityColumns(selectedDataset, datasetDescription) + const cols = municipalityColumns(selectedDataset, datasetDescription.columnHeader) const rankedData = rankData(municipalities, selectedDataset) const isDefaultDataView = selectedDataView === defaultDataView diff --git a/pages/[dataset]/[dataView]/index.tsx b/pages/[dataset]/[dataView]/index.tsx index 00409ab5..ab2b3df2 100644 --- a/pages/[dataset]/[dataView]/index.tsx +++ b/pages/[dataset]/[dataView]/index.tsx @@ -1,11 +1,12 @@ import { GetServerSideProps } from 'next' import { ParsedUrlQuery } from 'querystring' -import { Municipality as TMunicipality } from '../../../utils/types' +import { Company as TCompany, Municipality as TMunicipality } from '../../../utils/types' import StartPage from '../..' import { ClimateDataService } from '../../../utils/climateDataService' import { isValidDataset, isValidDataView, normalizeString } from '../../../utils/shared' import Layout from '../../../components/Layout' import Footer from '../../../components/Footer/Footer' +import { CompanyDataService } from '../../../utils/companyDataService' interface Params extends ParsedUrlQuery { dataset: string @@ -35,17 +36,27 @@ export const getServerSideProps: GetServerSideProps = async ({ params, res }) => } const municipalities = new ClimateDataService().getMunicipalities() - if (municipalities.length < 1) throw new Error('No municipalities found') + if (municipalities.length < 1) { + throw new Error('No municipalities found') + } + + const companies = new CompanyDataService().getCompanies() + if (companies.length < 1) { + throw new Error('No companies found') + } res.setHeader( 'Cache-Control', `public, stale-while-revalidate=60, max-age=${60 * 60 * 24 * 7}`, ) - if (cache.get(normalizedDataset)) return cache.get(normalizedDataset) + if (cache.get(normalizedDataset)) { + return cache.get(normalizedDataset) + } const result = { props: { + companies, municipalities, normalizedDataset, }, @@ -56,14 +67,15 @@ export const getServerSideProps: GetServerSideProps = async ({ params, res }) => } type Props = { + companies: Array municipalities: Array } -export default function DataView({ municipalities }: Props) { +export default function DataView({ companies, municipalities }: Props) { return ( <> - +