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

Publish new company list to production #649

Merged
merged 10 commits into from
Jun 18, 2024
44 changes: 0 additions & 44 deletions components/CompanyView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,35 +68,6 @@ const ComparisonContainer = styled.div`
display: flex;
`

const Details = styled.div`
display: grid;
padding: 0 6px 8px;

@media only screen and (${devices.tablet}) {
padding: 8px 12px 16px;
}
`

const DetailsHeader = styled.div`
display: flex;
justify-content: space-between;
gap: 0.5rem;

p {
font-style: italic;
color: ${({ theme }) => theme.newColors.gray};
padding-top: 0.5rem;
}

a {
padding: 0.5rem 0;
}

@media only screen and (${devices.tablet}) {
padding-bottom: 0.5rem;
}
`

type CompanyViewProps = {
companies: Array<Company>
}
Expand All @@ -116,21 +87,6 @@ function CompanyView({
data={companies}
columns={cols}
dataType="companies"
renderSubComponent={({ row }) => {
const company = row.original
return (
<Details>
<DetailsHeader>
<p>
{t('common:comment')}
:
</p>
<a href={company.Url} target="_blank" rel="noopener noreferrer">{t('startPage:companyView.readReport')}</a>
</DetailsHeader>
<p>{company.Comment}</p>
</Details>
)
}}
/>
</ComparisonContainer>
<InfoText>
Expand Down
201 changes: 110 additions & 91 deletions components/ComparisonTable.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import {
Fragment, useEffect, useState,
} from 'react'
import { useEffect, useState } from 'react'
import { useRouter } from 'next/router'
import styled from 'styled-components'
import {
Expand All @@ -10,12 +8,13 @@ import {
SortingState,
getSortedRowModel,
Row,
getExpandedRowModel,
} from '@tanstack/react-table'
import type { ColumnDef } from '@tanstack/react-table'

import { devices } from '../utils/devices'
import ArrowIcon from '../public/icons/arrow-right-bold-green.svg'
import { Company } from '../utils/types'
import InfoModal from './InfoModal'

const StyledTable = styled.table`
--margin: 4px;
Expand All @@ -29,7 +28,7 @@ const StyledTable = styled.table`
@media only screen and (${devices.smallMobile}) {
font-size: 0.85em;
}

@media only screen and (${devices.tablet}) {
--margin: 8px;
font-size: 1em;
Expand Down Expand Up @@ -118,10 +117,9 @@ const TableHeaderInner = styled.span`
grid-template-columns: 1fr max-content;
`

const TableRow = styled.tr<{ interactive?: boolean, showBorder?: boolean, isExpanded?: boolean }>`
border-bottom: ${({ showBorder, theme }) => (showBorder ? `1px solid ${theme.newColors.blue3}` : '')};
cursor: ${({ interactive }) => (interactive ? 'pointer' : '')};
background: ${({ isExpanded, theme }) => (isExpanded ? theme.newColors.black1 : '')};
const TableRow = styled.tr`
border-bottom: 1px solid ${({ theme }) => theme.newColors.blue3};
cursor: pointer;
z-index: 10;
`

Expand All @@ -134,17 +132,21 @@ type TableProps<T extends object> = {
columns: ColumnDef<T>[]
// IDEA: It might be better to turn ComparisionTable into two specific components, one for every use case
dataType?: 'municipalities' | 'companies'
renderSubComponent?: ({ row }: { row: Row<T> }) => JSX.Element
}

/**
* Make sure the first column has an id, and prepare default sorting.
*/
function prepareColumnsForDefaultSorting<T extends object>(columns: TableProps<T>['columns']) {
function prepareColumnsForDefaultSorting<T extends object>(
columns: TableProps<T>['columns'],
) {
const preparedColumns = columns[0].id
? columns
// @ts-expect-error accessorKey does exist, but there's a type error somewhere.
: [{ ...columns[0], id: (columns[0].accessorKey).replace('.', '_') }, ...columns.slice(1)]
: [
// @ts-expect-error accessorKey does exist, but there's a type error somewhere.
{ ...columns[0], id: columns[0].accessorKey.replace('.', '_') },
...columns.slice(1),
]

const defaultSorting = [{ id: preparedColumns[0].id!, desc: false }]

Expand All @@ -155,21 +157,36 @@ function ComparisonTable<T extends object>({
data,
columns,
dataType = 'municipalities',
renderSubComponent,
}: TableProps<T>) {
const { preparedColumns, defaultSorting } = prepareColumnsForDefaultSorting(columns)
const [sorting, setSorting] = useState<SortingState>(defaultSorting)
const router = useRouter()
const [resizeCount, setResizeCount] = useState(0)
const [isModalOpen, setIsModalOpen] = useState(false)
const [modalText, setModalText] = useState('')

const showModal = (text: string) => {
setModalText(text)
setIsModalOpen(true)
document.body.style.overflow = 'hidden'
}

const toggleModal = () => {
if (!isModalOpen) {
document.body.style.overflow = 'hidden'
setIsModalOpen(true)
} else {
document.body.style.overflow = ''
setIsModalOpen(false)
}
}

useEffect(() => {
const handleResize = () => setResizeCount((count) => count + 1)
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [])

const enableExpanding = typeof renderSubComponent === 'function'

const isDataColumn = (index: number) => {
if (dataType === 'companies') {
return index > 0
Expand All @@ -183,96 +200,98 @@ function ComparisonTable<T extends object>({
columns: preparedColumns,
state: { sorting },
onSortingChange: setSorting,
enableExpanding,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getExpandedRowModel: getExpandedRowModel(),
enableSortingRemoval: false,
})

const handleRowClick = (row: Row<T>) => {
if (dataType === 'municipalities') {
const cells = row.getAllCells()
const value = cells.at(1)?.renderValue()
const route = `/kommun/${(value as unknown as string).toLowerCase()}`
router.push(route)
} else if (dataType === 'companies') {
row.toggleExpanded()
const cells = row.getAllCells()
const columnIndex = dataType === 'companies' ? 0 : 1
const value = cells.at(columnIndex)?.renderValue()
const lowerCaseName = (value as unknown as string).toLowerCase()

if (dataType === 'companies') {
const wikiId = (row.original as Company).WikiId
if (!wikiId) {
showModal(`### ${value}\n\n${(row.original as Company).Comment}`)
return
}

const dashName = lowerCaseName.replaceAll(' ', '-')
const url = process.env.NODE_ENV === 'production' ? 'https://beta.klimatkollen.se' : 'http://localhost:4321'
const companyRoute = `${url}/foretag/${dashName}-${wikiId}`
window.location.href = companyRoute
} else {
const municipalityrRoute = `/kommun/${lowerCaseName}`
router.push(municipalityrRoute)
}
}

return (
<StyledTable key={resizeCount}>
{/* HACK: prevent table headers from changing size when toggling table rows. Not sure what causes the problem, but this fixes it. */}
{dataType === 'companies' ? (
<colgroup>
<col width="35%" />
<col width="30%" />
<col width="35%" />
</colgroup>
) : null}

<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
const currentSort = header.column.getIsSorted()
return (
<>
<StyledTable key={resizeCount}>
{/* HACK: prevent table headers from changing size when toggling table rows. Not sure what causes the problem, but this fixes it. */}
{dataType === 'companies' ? (
<colgroup>
<col width="35%" />
<col width="30%" />
<col width="35%" />
</colgroup>
) : null}

<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
const currentSort = header.column.getIsSorted()
return (
// TODO: Ensure clicking table headers doesn't scroll to top.
// It almost seems like this could be by the table losing all its content
// just before re-rendering it. And since the table (or page) doesn't need as much scroll anymore,
// maybe it just shows the top of the table then again?
<TableHeader
key={header.id}
colSpan={header.colSpan}
className={isDataColumn(header.index) ? 'data-header' : ''}
onClick={header.column.getToggleSortingHandler()}
onKeyDown={header.column.getToggleSortingHandler()}
<TableHeader
key={header.id}
colSpan={header.colSpan}
className={isDataColumn(header.index) ? 'data-header' : ''}
onClick={header.column.getToggleSortingHandler()}
onKeyDown={header.column.getToggleSortingHandler()}
>
<TableHeaderInner data-sorting={header.column.getIsSorted()}>
{header.isPlaceholder
? null
: flexRender(header.column.columnDef.header, header.getContext())}
{currentSort ? (
<SortingIcon
style={{
transform: `scale(0.6) rotate(${currentSort === 'desc' ? '' : '-'}90deg)`,
}}
/>
) : null}
</TableHeaderInner>
</TableHeader>
)
})}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<TableRow onClick={() => handleRowClick(row)} key={row.id}>
{row.getVisibleCells().map((cell, index) => (
<TableData
key={cell.id}
className={isDataColumn(index) ? 'data-column' : ''}
>
<TableHeaderInner data-sorting={header.column.getIsSorted()}>
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
{currentSort ? (
<SortingIcon
style={{ transform: `scale(0.6) rotate(${currentSort === 'desc' ? '' : '-'}90deg)` }}
/>
) : null}
</TableHeaderInner>
</TableHeader>
)
})}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => {
const isRowExpanded = enableExpanding && row.getIsExpanded()
return (
<Fragment key={row.id}>
<TableRow
onClick={() => handleRowClick(row)}
interactive={enableExpanding || dataType === 'municipalities'}
showBorder={enableExpanding ? !isRowExpanded : true}
isExpanded={isRowExpanded}
aria-expanded={isRowExpanded}
>
{row.getVisibleCells().map((cell, index) => (
<TableData key={cell.id} className={isDataColumn(index) ? 'data-column' : ''}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableData>
))}
</TableRow>
{isRowExpanded && (
<TableRow showBorder>
<td colSpan={row.getVisibleCells().length}>
{renderSubComponent({ row })}
</td>
</TableRow>
)}
</Fragment>
)
})}
</tbody>
</StyledTable>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableData>
))}
</TableRow>
))}
</tbody>
</StyledTable>
{isModalOpen && <InfoModal text={modalText} close={toggleModal} scrollY={window.scrollY} />}
</>
)
}

Expand Down
4 changes: 2 additions & 2 deletions components/InfoModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import styled from 'styled-components'
import { useTranslation } from 'next-i18next'

import Close from '../public/icons/close.svg'
import { Paragraph } from './Typography'
import { IconButton } from './shared'
import { devices } from '../utils/devices'
import Markdown from './Markdown'

const Modal = styled.div<{ scrollY: number }>`
background-color: rgba(0, 0, 0, 0.5);
Expand Down Expand Up @@ -120,7 +120,7 @@ function InfoModal({ text, close, scrollY }: Props) {
<IconButton type="button" aria-label={t('common:actions.close')} onClick={close}>
<Close />
</IconButton>
<Paragraph>{text}</Paragraph>
<Markdown>{text}</Markdown>
</div>
</div>
</Modal>
Expand Down
2 changes: 1 addition & 1 deletion data/companies/company-data.json

Large diffs are not rendered by default.

Binary file modified data/companies/companyData.xlsx
Binary file not shown.
4 changes: 2 additions & 2 deletions data/companies/company_emission_calculations.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
df = pd.read_excel("companyData.xlsx", sheet_name="SiteData")

# Select the desired columns
selected_columns = ['Company', 'URL 2023', 'Scope 1+2', 'Scope 3 (total)', 'Alex kommentar']
selected_columns = ['Company', 'Wiki id', 'URL 2023', 'Scope 1+2', 'Scope 3 (total)', 'Alex kommentar']
selected_df = df[selected_columns]

# Strip leading and trailing whitespaces from all string columns
selected_df = selected_df.map(lambda x: x.strip() if isinstance(x, str) else x)

# Rename the columns for clarity
selected_df.columns = ['Company', 'URL', 'Scope1n2', 'Scope3', 'Comment']
selected_df.columns = ['Company', 'WikiId', 'URL', 'Scope1n2', 'Scope3', 'Comment']

# Prefer null values to make it clear when data is missing
selected_df.replace('n.a', None, inplace=True)
Expand Down
1 change: 1 addition & 0 deletions utils/companyDataService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class CompanyDataService {
return {
Name: data.Company,
Url: data.URL,
WikiId: data.WikiId,
Comment: data.Comment,
Emissions: emissionsPerYear,
} as unknown as Company
Expand Down
Loading
Loading