Skip to content

Commit

Permalink
Fix 347 add sitemap and robots.txt (#404)
Browse files Browse the repository at this point in the history
* Add sitemap.xml.ts and robots.txt files

* Add tests for generating municipality sitemap data and sitemap XML string

* Update robots.txt

fixed typo

* Move replaceLetters function to shared  and use it in generateMunipacitySitemapData

* Run eslint -fix
  • Loading branch information
Braggedtooth authored Mar 18, 2024
1 parent f6694bf commit f5c01f2
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 25 deletions.
33 changes: 33 additions & 0 deletions __tests__/utils/generateMunipacitySitemap.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {
generateMunipacitySitemapData,
generateSitemap,
} from '../../utils/generateMunipacitySitemap'
import { Municipality } from '../../utils/types'

const municipalities = [{ Name: 'Stockholm' }, { Name: 'Göteborg' }] as Municipality[]
describe('generateSitemap', () => {
it('should generate valid municipality sitemap data', () => {
const siteMap = generateMunipacitySitemapData({ municipalities })
expect(siteMap).toEqual([
{
url: 'https://klimatkollen.se/kommun/Stockholm',
name: 'Stockholm',
lastModified: expect.any(Date),
changeFrequency: 'yearly',
priority: 1,
},
{
url: 'https://klimatkollen.se/kommun/Göteborg',
name: 'Göteborg',
lastModified: expect.any(Date),
changeFrequency: 'yearly',
priority: 1,
},
])
})
it('should generate a valid sitemap XML string', () => {
const siteMap = generateMunipacitySitemapData({ municipalities })
const sitemapXml = generateSitemap(siteMap)
expect(() => new DOMParser().parseFromString(sitemapXml, 'text/xml')).not.toThrow()
})
})
32 changes: 7 additions & 25 deletions components/Map/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useRouter } from 'next/router'
import NextNProgress from 'nextjs-progressbar'
import { colorTheme } from '../../Theme'
import { mapColors } from '../shared'
import { replaceLetters } from '../../utils/shared'

const INITIAL_VIEW_STATE = {
longitude: 17.062927,
Expand Down Expand Up @@ -65,36 +66,17 @@ const getColor = (
return colors[5]
}

const replaceLetters = (name: string): string => {
const replacements: Record<string, string> = {
'Ã¥': 'å',
'ä': 'ä',
'ö': 'ö',
'Ã…': 'Å',
'Ä': 'Ä',
'Ö': 'Ö',
}

const regex = new RegExp(Object.keys(replacements).join('|'), 'g')

return name.replace(regex, (match) => replacements[match])
}

// Use when viewState is reimplemented
/* const MAP_RANGE = {
lon: [8.107180004121693, 26.099158344940808],
lat: [61.9, 63.9],
} */

type Props = {
data: Array<{ name: string; dataPoint: number | string | Date; formattedDataPoint: number | string }>
data: Array<{
name: string
dataPoint: number | string | Date
formattedDataPoint: number | string
}>
boundaries: number[] | string[] | Date[]
children?: ReactNode
}

function Map({
data, boundaries, children,
}: Props) {
function Map({ data, boundaries, children }: Props) {
const [municipalityData, setMunicipalityData] = useState<any>({})
const router = useRouter()

Expand Down
28 changes: 28 additions & 0 deletions pages/sitemap.xml.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// pages/sitemap.xml.js

import { NextApiResponse } from 'next'
import { ClimateDataService } from '../utils/climateDataService'
import {
generateMunipacitySitemapData,
generateSitemap,
} from '../utils/generateMunipacitySitemap'

export async function getServerSideProps({ res }: { res: NextApiResponse }) {
const municipalities = new ClimateDataService().getMunicipalities()
const municipalitiesSitemap = generateMunipacitySitemapData({
municipalities,
})
// Generate the XML sitemap with the blog data
const sitemap = generateSitemap(municipalitiesSitemap)

res.setHeader('Content-Type', 'text/xml')
// Send the XML to the browser
res.write(sitemap)
res.end()

return {
props: {},
}
}

export default function SiteMap() {}
3 changes: 3 additions & 0 deletions public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
User-agent: *
Disallow:
Sitemap: https://klimatkollen.se/sitemap.xml
59 changes: 59 additions & 0 deletions utils/generateMunipacitySitemap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { replaceLetters } from './shared'
import { Municipality } from './types'

type SiteMap = {
url: string
lastModified: Date
changeFrequency: string
priority: number
name?: string
}
const BASE_URL = 'https://klimatkollen.se'
export const generateMunipacitySitemapData = ({
municipalities,
}: {
municipalities: Municipality[]
}): SiteMap[] => municipalities.map((m) => ({
url: `${BASE_URL}/kommun/${replaceLetters(m.Name).toLowerCase()}`,
name: m.Name,
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 1,
}))
export const generateSitemap = (
siteMap: SiteMap[],
) => `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>${BASE_URL}/utslappen/karta</loc>
<name>Utsläppskarta</name>
<lastmod>${new Date().toISOString()}</lastmod>
<changefreq>yearly</changefreq>
</url>
<url>
<loc>${BASE_URL}/om-oss</loc>
<name>Om oss</name>
<lastmod>${new Date().toISOString()}</lastmod>
<changefreq>monthly</changefreq>
</url>
<url>
<loc>${BASE_URL}/in-english</loc>
<name>In English</name>
<lastmod>${new Date().toISOString()}</lastmod>
<changefreq>monthly</changefreq>
</url>
${siteMap
.map(
(s) => `
<url>
<loc>${s.url}</loc>
<name>${s.name}</name>
<lastmod>${s.lastModified.toISOString()}</lastmod>
<changefreq>${s.changeFrequency}</changefreq>
<priority>${s.priority}</priority>
</url>
`,
)
.join('')}
</urlset>
`
15 changes: 15 additions & 0 deletions utils/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,18 @@ export const isValidDataset = (dataset: string) => {
}

export const isValidDataView = (dataView: string) => [defaultDataView, secondaryDataView].includes(dataView)

export const replaceLetters = (name: string): string => {
const replacements: Record<string, string> = {
'Ã¥': 'å',
'ä': 'ä',
'ö': 'ö',
'Ã…': 'Å',
'Ä': 'Ä',
'Ö': 'Ö',
}

const regex = new RegExp(Object.keys(replacements).join('|'), 'g')

return name.replace(regex, (match) => replacements[match])
}

0 comments on commit f5c01f2

Please sign in to comment.