Skip to content

Commit

Permalink
Implement view counter
Browse files Browse the repository at this point in the history
  • Loading branch information
wzulfikar committed Apr 26, 2021
1 parent e9729a2 commit 249e0bd
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 14 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
# Optional (for preview image support)
#FIREBASE_COLLECTION_IMAGES=

# Optional (for view counter support)
#FIREBASE_COLLECTION_PAGEVIEWS=

# Optional (for fathom analytics)
#NEXT_PUBLIC_FATHOM_ID=
#NEXT_PUBLIC_FATHOM_SCRIPT_URL=
Expand Down
30 changes: 16 additions & 14 deletions components/NotionPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { Footer } from './Footer'
import { PageSocial } from './PageSocial'
import { GitHubShareButton } from './GitHubShareButton'
import { ReactUtterances } from './ReactUtterances'
import { ViewCounter } from './ViewCounter'

import styles from './styles.module.css'

Expand Down Expand Up @@ -124,8 +125,9 @@ export const NotionPage: React.FC<types.PageProps> = ({

const siteMapPageUrl = mapPageUrl(site, recordMap, searchParams)

const canonicalPageUrl =
!config.isDev && getCanonicalPageUrl(site, recordMap)(pageId)
const pageUrl = getCanonicalPageUrl(site, recordMap)(pageId)
const canonicalPageUrl = !config.isDev && pageUrl
const slug = new URL(pageUrl).pathname.substr(1).replace(`-${pageId}`, '')

// const isRootPage =
// parsePageId(block.id) === parsePageId(site.rootNotionPageId)
Expand Down Expand Up @@ -163,13 +165,18 @@ export const NotionPage: React.FC<types.PageProps> = ({
if (isBlogPost) {
if (config.utterancesGitHubRepo) {
comments = (
<ReactUtterances
repo={config.utterancesGitHubRepo}
label={config.utterancesGitHubLabel}
issueMap='issue-term'
issueTerm='title'
theme={darkMode.value ? 'photon-dark' : 'github-light'}
/>
<>
<div style={{ marginLeft: 'auto', marginTop: '1rem' }}>
<ViewCounter slug={slug} />
</div>
<ReactUtterances
repo={config.utterancesGitHubRepo}
label={config.utterancesGitHubLabel}
issueMap='issue-term'
issueTerm='title'
theme={darkMode.value ? 'photon-dark' : 'github-light'}
/>
</>
)
}

Expand All @@ -194,7 +201,6 @@ export const NotionPage: React.FC<types.PageProps> = ({
}}
>
<PageHead site={site} />

<Head>
<meta property='og:title' content={title} />
<meta property='og:site_name' content={site.name} />
Expand Down Expand Up @@ -234,11 +240,8 @@ export const NotionPage: React.FC<types.PageProps> = ({

<title>{title}</title>
</Head>

<CustomFont site={site} />

{isLiteMode && <BodyClassName className='notion-lite' />}

<NotionRenderer
bodyClassName={cs(
styles.notion,
Expand Down Expand Up @@ -301,7 +304,6 @@ export const NotionPage: React.FC<types.PageProps> = ({
/>
}
/>

{config.showGithubRibbon && <GitHubShareButton />}
</TwitterContextProvider>
)
Expand Down
21 changes: 21 additions & 0 deletions components/ViewCounter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useEffect } from 'react'
import useSWR from 'swr'
import format from 'comma-number'

export function ViewCounter({ slug }) {
const { data } = useSWR(`/api/views/${slug}`, (args) =>
fetch(args).then((res) => res.json())
)
const views = data?.total

useEffect(() => {
const registerView = () =>
fetch(`/api/views/${slug}`, {
method: 'POST'
})

registerView()
}, [slug])

return <>{views ? format(views) : '––'} views</>
}
1 change: 1 addition & 0 deletions components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './NotionPage'
export * from './Page404'
export * from './ErrorPage'
export * from './ClientRedirect'
export * from './ViewCounter'
5 changes: 5 additions & 0 deletions lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ export const firebaseCollectionImages = getEnv(
defaultEnvValueForPreviewImageSupport
)

export const firebaseCollectionPageviews = getEnv(
'FIREBASE_COLLECTION_PAGEVIEWS',
'pageviews'
)

// this hack is necessary because vercel doesn't support secret files so we need to encode our google
// credentials a base64-encoded string of the JSON-ified content
function getGoogleApplicationCredentials() {
Expand Down
2 changes: 2 additions & 0 deletions lib/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as config from './config'

export let db: firestore.Firestore = null
export let images: firestore.CollectionReference = null
export let pageviews: firestore.CollectionReference = null

if (config.isPreviewImageSupportEnabled) {
db = new firestore.Firestore({
Expand All @@ -11,4 +12,5 @@ if (config.isPreviewImageSupportEnabled) {
})

images = db.collection(config.firebaseCollectionImages)
pageviews = db.collection(config.firebaseCollectionPageviews)
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@google-cloud/firestore": "^4.9.1",
"chrome-aws-lambda": "^5.5.0",
"classnames": "^2.2.6",
"comma-number": "^2.0.1",
"date-fns": "^2.19.0",
"fathom-client": "^3.0.0",
"got": "^11.8.1",
Expand All @@ -51,6 +52,7 @@
"react-static-tweets": "^0.5.3",
"react-use": "^15.3.3",
"static-tweets": "^0.5.3",
"swr": "^0.5.5",
"use-dark-mode": "^2.3.1"
},
"devDependencies": {
Expand Down
29 changes: 29 additions & 0 deletions pages/api/views/[slug].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as firestore from '@google-cloud/firestore'
import * as db from '@lib/db'

export default async function handler(req, res) {
if (req.method === 'POST') {
const increment = firestore.FieldValue.increment(1)

const allRef = db.pageviews.doc('all')
const slugRef = db.pageviews.doc(req.query.slug)

const [, , views] = await Promise.all([
allRef.set({ count: increment }, { merge: true }),
slugRef.set({ count: increment }, { merge: true }),
(await slugRef.get()).data().count
])

return res.status(200).json({
total: views
})
}

if (req.method === 'GET') {
const snapshot = await db.pageviews.doc(req.query.slug).get()

const views = snapshot.data()?.count || 0

return res.status(200).json({ total: views })
}
}
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1295,6 +1295,11 @@ combined-stream@^1.0.8:
dependencies:
delayed-stream "~1.0.0"

comma-number@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/comma-number/-/comma-number-2.0.1.tgz#d01de3f207f00ccd593dcbcf17ac633bbb942b62"
integrity sha512-hrxY6UjA+tSUV5uZS2iOF8+/q7AACiq/zc9R6SO61MmOhrzNC0qXXh7g/jNYTm09fp6T40vQg15zkCmTJVA8Ww==

comma-separated-tokens@^1.0.0:
version "1.0.8"
resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea"
Expand Down Expand Up @@ -5471,6 +5476,13 @@ supports-color@^8.0.0:
dependencies:
has-flag "^4.0.0"

swr@^0.5.5:
version "0.5.5"
resolved "https://registry.yarnpkg.com/swr/-/swr-0.5.5.tgz#c72c1615765f33570a16bbb13699e3ac87eaaa3a"
integrity sha512-u4mUorK9Ipt+6LEITvWRWiRWAQjAysI6cHxbMmMV1dIdDzxMnswWo1CyGoyBHXX91CchxcuoqgFZ/ycx+YfhCA==
dependencies:
dequal "2.0.2"

swr@^1.0.0-beta.5:
version "1.0.0-beta.5"
resolved "https://registry.yarnpkg.com/swr/-/swr-1.0.0-beta.5.tgz#9087a4330934b71f73761ab7004a5a3ffc5c10c1"
Expand Down

0 comments on commit 249e0bd

Please sign in to comment.