Skip to content

Instantly share code, notes, and snippets.

View PaulieScanlon's full-sized avatar

Paul Scanlon PaulieScanlon

View GitHub Profile
@PaulieScanlon
PaulieScanlon / index.js
Created June 20, 2024 14:40
Report markdown string
// src/index.js#L42
const report = response.rows
.map((row, index) => {
const { dimensionValues, metricValues } = row;
return `${index + 1}. <https://${dimensionValues[0].value}|${dimensionValues[1].value}> | *x${
metricValues[0].value
}*`;
})
@PaulieScanlon
PaulieScanlon / index.js
Created June 20, 2024 14:38
Google Analytics query
// src/index.js#L16
const [response] = await analyticsDataClient.runReport({
property: `properties/${process.env.GA4_PROPERTY_ID}`,
dateRanges: [
{
startDate: '7daysAgo',
endDate: 'today',
},
],
# .github/workflows/analytics-report.yml
name: 7 Day Google Analytics Report
on:
schedule:
- cron: '0 10 * * 5' # Runs every Friday at 10 AM UTC
workflow_dispatch: # Allows manual triggering
jobs:
@PaulieScanlon
PaulieScanlon / get-all-votes.ts
Created June 16, 2024 14:40
Result Server Action
// app/results/get-all-votes.ts
'use server';
import { doc } from '../../services/google-spreadsheet';
import config from '../../utils/poll-config';
export default async function getAllVotes() {
try {
await doc.loadInfo();
@PaulieScanlon
PaulieScanlon / layout.tsx
Created June 16, 2024 14:38
Result layout
// app/layout.tsx
export const metadata = {
title: 'Results',
description: 'Generated by Next.js',
}
export default function RootLayout({
children,
}: {
@PaulieScanlon
PaulieScanlon / page.tsx
Created June 16, 2024 14:37
Result Page
// app/results/page.tsx
import Link from 'next/link';
import getAllVotes from './get-all-votes';
export default async function Page() {
const votes = await getAllVotes();
return (
@PaulieScanlon
PaulieScanlon / submit-vote.ts
Created June 16, 2024 14:35
Vote Server Action
// submit-vote.ts
'use server';
import { redirect } from 'next/navigation';
import { doc } from '../services/google-spreadsheet';
export default async function submitVote(id: string) {
if (!id) {
redirect('/?error=true');
}
@PaulieScanlon
PaulieScanlon / layout.tsx
Created June 16, 2024 14:34
Vote layout
// app/layout.tsx
export const metadata = {
title: 'Vote',
description: 'Generated by Next.js',
}
export default function RootLayout({
children,
}: {
// app/page.tsx
'use client';
import { useState } from 'react';
import config from '../utils/poll-config';
import submitVote from './submit-vote';
export default function Page({ searchParams }) {
const { error } = searchParams;
@PaulieScanlon
PaulieScanlon / poll-config.ts
Created June 16, 2024 14:30
Google Sheet config
// ./utils/poll-config.ts
const config = [
{
name: 'Frontend Development',
id: 'frontend_development',
},
{
name: 'Software Development',
id: 'software_development',