diff --git a/.github/workflows/development.yml b/.github/workflows/development.yml index 0f1c5bf..a4a4b16 100644 --- a/.github/workflows/development.yml +++ b/.github/workflows/development.yml @@ -7,6 +7,7 @@ on: jobs: deploy: + name: Deploy dev runs-on: ubuntu-latest strategy: matrix: diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 9bff604..356fc7e 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -7,6 +7,7 @@ on: jobs: deploy: + name: Deploy prod runs-on: ubuntu-latest strategy: matrix: @@ -25,6 +26,7 @@ jobs: env: NEXT_PUBLIC_CONTENTFUL_SPACE_ID: ${{ secrets.NEXT_PUBLIC_CONTENTFUL_SPACE_ID }} NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN: ${{ secrets.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN }} + TRACK_GA: ${{ secrets.GA_TRACKING_ID }} run: yarn build - name: Deploy to netlify diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c22a4c0..4381fd9 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -6,6 +6,7 @@ on: jobs: deploy: + name: Deploy production (Contentful) runs-on: ubuntu-latest strategy: matrix: @@ -29,6 +30,7 @@ jobs: env: NEXT_PUBLIC_CONTENTFUL_SPACE_ID: ${{ secrets.NEXT_PUBLIC_CONTENTFUL_SPACE_ID }} NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN: ${{ secrets.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN }} + TRACK_GA: ${{ secrets.GA_TRACKING_ID }} run: yarn build - name: Deploy to netlify diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index 2b09a96..19a9a46 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -7,6 +7,7 @@ on: jobs: deploy: + name: Deploy staging runs-on: ubuntu-latest strategy: matrix: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b96e7e8..63e9cc4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -52,15 +52,12 @@ jobs: - name: Install packages run: yarn - - name: Build app - env: - NEXT_PUBLIC_CONTENTFUL_SPACE_ID: ${{ secrets.NEXT_PUBLIC_CONTENTFUL_SPACE_ID }} - NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN: ${{ secrets.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN }} - run: yarn build - - name: Audit with Lighthouse CI uses: treosh/lighthouse-ci-action@v3 with: + urls: | + https://perjansson-dev.netlify.app + runs: 3 configPath: 'lighthouserc.js' uploadArtifacts: true temporaryPublicStorage: true diff --git a/components/header.tsx b/components/header.tsx index fb553a3..67e0153 100644 --- a/components/header.tsx +++ b/components/header.tsx @@ -1,15 +1,30 @@ import React from 'react' import { ContactsType } from '../types' +import { event } from '../utils/gtag' interface HeaderProps { contacts: ContactsType } export const Header: React.FC = ({ contacts }) => { + const handleOnContactClick = (medium: string) => + event({ + category: 'user_interaction', + action: 'contact_click', + label: medium, + value: 1, + }) + return (
{contacts.map(({ url, medium }) => ( - + handleOnContactClick(medium)} + > {medium} ))} diff --git a/components/projects.tsx b/components/projects.tsx index 50a6567..9cf60f7 100644 --- a/components/projects.tsx +++ b/components/projects.tsx @@ -1,10 +1,11 @@ -import React, { useRef, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import RichText from '@madebyconnor/rich-text-to-jsx' import { Fade } from 'react-awesome-reveal' import SmoothCollapse from 'react-smooth-collapse' import { ProjectsType, ProjectType } from '../types' -import { formatProjectDates } from '../utils' +import { formatProjectDates } from '../utils/projectHelper' +import { event } from '../utils/gtag' interface ProjectsProps { projects: ProjectsType @@ -16,9 +17,21 @@ export const Projects: React.FC = ({ projects }) => { >(undefined) const handleOnSelect = (project: ProjectType) => { - setSelectedProject((previouslySelectedProject) => - project !== previouslySelectedProject ? project : undefined - ) + setSelectedProject((previouslySelectedProject) => { + const newProject = + project !== previouslySelectedProject ? project : undefined + + if (newProject) { + event({ + category: 'user_interaction', + action: 'project_selected', + label: newProject.title, + value: 1, + }) + } + + return newProject + }) } return ( @@ -68,6 +81,7 @@ function Project({ project, odd, selected, onSelect }: ProjectProps) { city, tags, } = project + const lqipAssetUrl = asset ? `${asset.url}?fl=progressive&w=67&h=100` : undefined diff --git a/components/tagCloud.tsx b/components/tagCloud.tsx index 3381c55..0228f1b 100644 --- a/components/tagCloud.tsx +++ b/components/tagCloud.tsx @@ -5,12 +5,13 @@ import '@reach/slider/styles.css' import { formatProjectDates, - isMobile, projectTagsToTagCloudData, sortProjectsOnStartDate, yearFromIsoDate, -} from '../utils' +} from '../utils/projectHelper' +import isMobile from '../utils/isMobile' import { ProjectsType } from '../types' +import { event } from '../utils/gtag' const TAG_CLOUD_INITIAL_YEARS_OF_HISTORY = 5 const MIN_FONT_SIZE = { @@ -57,6 +58,13 @@ export const TagCloud: React.FC = memo(({ projects }) => { const handleSliderChange = (newMinYear: number) => { if (newMinYear !== selectedMinYear) { setSelectedMinYear(newMinYear) + + event({ + category: 'user_interaction', + action: 'tag_cloud_min_date_change', + label: newMinYear + '', + value: 1, + }) } } diff --git a/lighthouserc.js b/lighthouserc.js index 3f81187..787ab8e 100644 --- a/lighthouserc.js +++ b/lighthouserc.js @@ -1,9 +1,5 @@ module.exports = { ci: { - collect: { - numberOfRuns: 3, - staticDistDir: './out', - }, assert: { // preset: 'lighthouse:recommended', assertions: { diff --git a/package.json b/package.json index 6ff67e3..875015d 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "dev": "next dev", "build": "next build && next export", "start": "next start -p $PORT", + "start:static": "yarn build && serve ./out", "start:ci": "next start -p 5000", "test:e2e": "cypress run", "test:e2e:open": "cypress open", @@ -28,6 +29,7 @@ }, "devDependencies": { "@contentful/rich-text-types": "^14.1.2", + "@types/gtag.js": "^0.0.4", "@types/react": "^17.0.0", "@types/react-tagcloud": "^1.1.5", "@types/smoothscroll-polyfill": "^0.3.1", @@ -39,6 +41,7 @@ "eslint-plugin-react": "^7.21.5", "eslint-plugin-react-hooks": "^4.2.0", "prettier": "2.1.2", + "serve": "^11.3.2", "start-server-and-test": "^1.11.5", "typescript": "^4.1.3" } diff --git a/pages/_app.tsx b/pages/_app.tsx index 94e71a3..5bf3f12 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,17 +1,34 @@ -import React from 'react' +import React, { useEffect } from 'react' import Head from 'next/head' import { AppProps } from 'next/app' +import { useRouter } from 'next/router' -const App: React.FC = ({ Component, pageProps }) => ( - <> - - - - - -) +import * as gtag from '../utils/gtag' + +const App: React.FC = ({ Component, pageProps }) => { + const router = useRouter() + + useEffect(() => { + const handleRouteChange = (url: URL) => { + gtag.pageview(url) + } + router.events.on('routeChangeComplete', handleRouteChange) + return () => { + router.events.off('routeChangeComplete', handleRouteChange) + } + }, [router.events]) + + return ( + <> + + + + + + ) +} export default App diff --git a/pages/_document.js b/pages/_document.js index fa4eec1..8d1bcb2 100644 --- a/pages/_document.js +++ b/pages/_document.js @@ -37,7 +37,6 @@ class MyDocument extends Document { - - + {process.env.GA_TRACKING_ID && ( + <> +