Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ on:
- main

permissions:
contents: read # Access to repository content for build and deploy
contents: read # Access to repository content for build and deploy

jobs:
build_and_deploy_job:
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
runs-on: ubuntu-latest
name: Build and Deploy Job
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
with:
submodules: true
lfs: false
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/gitleaks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
name: gitleaks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
persist-credentials: false
fetch-depth: 0
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/zizmor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
persist-credentials: false

Expand Down
49 changes: 49 additions & 0 deletions app/beta/[platform]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { NextRequest, NextResponse } from 'next/server';

import { betaRedirectClicks, db } from '@/db/schema';

const destinations: Record<string, Record<string, string>> = {
android: {
testing: 'https://play.google.com/apps/testing/com.slayspeech.app',
store: 'https://play.google.com/store/apps/details?id=com.slayspeech.app',
},
};

const cleanParam = (value: string | null, maxLength: number) => {
const trimmed = value?.trim();
if (!trimmed) return null;
return trimmed.slice(0, maxLength);
};

export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ platform: string }> },
) {
const { platform: rawPlatform } = await params;
const platform = rawPlatform.toLowerCase();
const searchParams = request.nextUrl.searchParams;
const destination = cleanParam(searchParams.get('destination'), 64) || 'testing';
const target = destinations[platform]?.[destination];

if (!target) {
return NextResponse.json({ error: 'Unsupported beta redirect target' }, { status: 404 });
}

try {
await db.insert(betaRedirectClicks).values({
platform,
destination,
campaign: cleanParam(searchParams.get('campaign') || searchParams.get('utm_campaign'), 128),
variant: cleanParam(searchParams.get('variant') || searchParams.get('utm_content'), 128),
source: cleanParam(searchParams.get('source') || searchParams.get('utm_source'), 128),
medium: cleanParam(searchParams.get('medium') || searchParams.get('utm_medium'), 128),
recipientId: cleanParam(searchParams.get('recipient_id'), 128),
referrer: cleanParam(request.headers.get('referer'), 2048),
userAgent: cleanParam(request.headers.get('user-agent'), 2048),
});
} catch (error) {
console.error('Failed to record beta redirect click', error);
}

return NextResponse.redirect(target, { status: 302 });
}
16 changes: 6 additions & 10 deletions app/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import Header from '@/components/ui/1 - header';
import CTA from '@/components/sections/3 - CTA';
import Footer from '@/components/sections/4 - Footer';

export async function generateMetadata({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug);
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const post = await getPost(slug);
if (!post) return {};

return {
Expand Down Expand Up @@ -38,14 +39,9 @@ export async function generateMetadata({ params }: { params: { slug: string } })
};
}

export default async function PostPage({
params,
}: {
params: {
slug: string;
};
}) {
const post = await getPost(params.slug);
export default async function PostPage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const post = await getPost(slug);
if (!post) return notFound();

return (
Expand Down
12 changes: 6 additions & 6 deletions components/ui/base/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function DialogClose({ ...props }) {
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
}

function DialogOverlay({ className, ...props }) {
function DialogOverlay({ className = '', ...props }) {
return (
<DialogPrimitive.Overlay
data-slot="dialog-overlay"
Expand All @@ -35,7 +35,7 @@ function DialogOverlay({ className, ...props }) {
);
}

function DialogContent({ className, children, ...props }) {
function DialogContent({ className = '', children, ...props }) {
return (
<DialogPortal data-slot="dialog-portal">
<DialogOverlay />
Expand All @@ -57,7 +57,7 @@ function DialogContent({ className, children, ...props }) {
);
}

function DialogHeader({ className, ...props }) {
function DialogHeader({ className = '', ...props }) {
return (
<div
data-slot="dialog-header"
Expand All @@ -67,7 +67,7 @@ function DialogHeader({ className, ...props }) {
);
}

function DialogFooter({ className, ...props }) {
function DialogFooter({ className = '', ...props }) {
return (
<div
data-slot="dialog-footer"
Expand All @@ -77,7 +77,7 @@ function DialogFooter({ className, ...props }) {
);
}

function DialogTitle({ className, ...props }) {
function DialogTitle({ className = '', ...props }) {
return (
<DialogPrimitive.Title
data-slot="dialog-title"
Expand All @@ -87,7 +87,7 @@ function DialogTitle({ className, ...props }) {
);
}

function DialogDescription({ className, ...props }) {
function DialogDescription({ className = '', ...props }) {
return (
<DialogPrimitive.Description
data-slot="dialog-description"
Expand Down
16 changes: 15 additions & 1 deletion db/schema.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { pgTable, varchar, integer, timestamp } from 'drizzle-orm/pg-core';
import { pgTable, varchar, integer, timestamp, serial, text } from 'drizzle-orm/pg-core';
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';

Expand All @@ -20,3 +20,17 @@ export const users = pgTable('users', {
.defaultNow()
.$onUpdate(() => new Date()),
});

export const betaRedirectClicks = pgTable('beta_redirect_clicks', {
id: serial('id').primaryKey(),
platform: varchar('platform', { length: 32 }).notNull(),
destination: varchar('destination', { length: 64 }).notNull(),
campaign: varchar('campaign', { length: 128 }),
variant: varchar('variant', { length: 128 }),
source: varchar('source', { length: 128 }),
medium: varchar('medium', { length: 128 }),
recipientId: varchar('recipient_id', { length: 128 }),
referrer: text('referrer'),
userAgent: text('user_agent'),
createdAt: timestamp('created_at', { mode: 'date', precision: 3 }).notNull().defaultNow(),
});
1 change: 1 addition & 0 deletions middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const PUBLIC_URLS = [
new RegExp('^/pricing$'),
new RegExp('^/about$'),
new RegExp('^/contact$'),
new RegExp('^/beta/.*$'),
];

export async function middleware(request: NextRequest) {
Expand Down
13 changes: 13 additions & 0 deletions migrations/0002_beta_redirect_clicks.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CREATE TABLE IF NOT EXISTS "beta_redirect_clicks" (
"id" serial PRIMARY KEY NOT NULL,
"platform" varchar(32) NOT NULL,
"destination" varchar(64) NOT NULL,
"campaign" varchar(128),
"variant" varchar(128),
"source" varchar(128),
"medium" varchar(128),
"recipient_id" varchar(128),
"referrer" text,
"user_agent" text,
"created_at" timestamp (3) DEFAULT now() NOT NULL
);
148 changes: 148 additions & 0 deletions migrations/meta/0002_snapshot.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
{
"id": "5fc88f2f-e84e-4c46-918b-c2ed3c08cd21",
"prevId": "ea981418-b0c7-40b4-ad88-4be6ea95338c",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.beta_redirect_clicks": {
"name": "beta_redirect_clicks",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"platform": {
"name": "platform",
"type": "varchar(32)",
"primaryKey": false,
"notNull": true
},
"destination": {
"name": "destination",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"campaign": {
"name": "campaign",
"type": "varchar(128)",
"primaryKey": false,
"notNull": false
},
"variant": {
"name": "variant",
"type": "varchar(128)",
"primaryKey": false,
"notNull": false
},
"source": {
"name": "source",
"type": "varchar(128)",
"primaryKey": false,
"notNull": false
},
"medium": {
"name": "medium",
"type": "varchar(128)",
"primaryKey": false,
"notNull": false
},
"recipient_id": {
"name": "recipient_id",
"type": "varchar(128)",
"primaryKey": false,
"notNull": false
},
"referrer": {
"name": "referrer",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_agent": {
"name": "user_agent",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.users": {
"name": "users",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"streak": {
"name": "streak",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 0
},
"stripe_id": {
"name": "stripe_id",
"type": "varchar",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}
9 changes: 8 additions & 1 deletion migrations/meta/_journal.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
"when": 1728112130005,
"tag": "0001_zippy_snowbird",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1782260000000,
"tag": "0002_beta_redirect_clicks",
"breakpoints": true
}
]
}
}
Loading