Skip to content

Commit cdcf1ae

Browse files
author
Miriad
committed
Merge branch 'dev'
# Conflicts: # app/(main)/(user)/dashboard/bookmarks/bookmarks.tsx # app/(main)/(user)/settings/account/subscriptions.tsx # app/(main)/(user)/settings/profile/profile.tsx # app/(main)/(user)/settings/profile/upload-profile-image.tsx # biome.json # components.json # components/become-sponsor-popup.tsx # components/ui/chart.tsx # components/ui/resizable.tsx # package.json # pnpm-lock.yaml # sanity.config.ts # sanity/extract.json # sanity/types.ts # vercel.json
2 parents 8e59621 + 79d5963 commit cdcf1ae

File tree

100 files changed

+17439
-32129
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+17439
-32129
lines changed

.env.example

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# =============================================================================
2+
# codingcat.dev — Environment Variables
3+
# =============================================================================
4+
# Copy this file to .env.local and fill in the values.
5+
# See: https://nextjs.org/docs/app/building-your-application/configuring/environment-variables
6+
# Variables prefixed with NEXT_PUBLIC_ are exposed to the browser.
7+
# All other variables are server-only.
8+
# =============================================================================
9+
10+
# -----------------------------------------------------------------------------
11+
# Public (client-side) variables — NEXT_PUBLIC_*
12+
# -----------------------------------------------------------------------------
13+
14+
# Sanity CMS — project configuration
15+
NEXT_PUBLIC_SANITY_PROJECT_ID= # Sanity project ID (from sanity.io/manage)
16+
NEXT_PUBLIC_SANITY_DATASET= # Sanity dataset name (e.g. "prod")
17+
NEXT_PUBLIC_SANITY_API_VERSION= # Sanity API version date (e.g. "2024-01-01")
18+
19+
# Site URLs
20+
NEXT_PUBLIC_BASE_URL= # Canonical base URL (e.g. "https://codingcat.dev")
21+
NEXT_PUBLIC_VERCEL_URL= # Vercel preview URL (auto-set by Vercel)
22+
23+
# Algolia search — public keys
24+
NEXT_PUBLIC_ALGOLIA_APP_ID= # Algolia application ID
25+
NEXT_PUBLIC_ALGOLIA_INDEX= # Algolia index name
26+
27+
# Analytics
28+
NEXT_PUBLIC_FB_PIXEL_ID= # Facebook Pixel tracking ID
29+
30+
# Preview mode
31+
NEXT_PUBLIC_PREVIEW_TOKEN_SECRET= # Secret token for Sanity preview mode
32+
33+
# -----------------------------------------------------------------------------
34+
# Server-only variables
35+
# -----------------------------------------------------------------------------
36+
37+
# Sanity CMS — API tokens
38+
SANITY_API_READ_TOKEN= # Sanity read token (viewer role)
39+
SANITY_API_WRITE_TOKEN= # Sanity write token (editor role)
40+
41+
# Algolia search — admin keys
42+
PRIVATE_ALGOLIA_ADMIN_API_KEY= # Algolia admin API key (server-side indexing)
43+
PRIVATE_ALGOLIA_WEBOOK_SECRET= # Shared secret for Algolia webhook verification
44+
45+
# Syndication
46+
PRIVATE_SYNDICATE_WEBOOK_SECRET= # Shared secret for syndication webhook verification
47+
PRIVATE_DEVTO= # Dev.to API key (cross-posting)
48+
PRIVATE_HASHNODE= # Hashnode API key (cross-posting)
49+
50+
# Cloudflare Turnstile (bot protection)
51+
CLOUDFLARE_TURNSTILE_SECRET_KEY= # Turnstile server-side secret key
52+
53+
# Cron / scheduled jobs
54+
CRON_SECRET= # Secret for authenticating cron job requests
55+
56+
# YouTube integration
57+
YOUTUBE_API_KEY= # YouTube Data API v3 key
58+
YOUTUBE_CHANNEL_ID= # YouTube channel ID to fetch videos from
59+
60+
# Vercel
61+
VERCEL_PROJECT_PRODUCTION_URL= # Production URL (auto-set by Vercel)
62+
63+
# -----------------------------------------------------------------------------
64+
# Supabase
65+
# -----------------------------------------------------------------------------
66+
NEXT_PUBLIC_SUPABASE_URL= # Supabase project URL (e.g. "https://xxx.supabase.co")
67+
NEXT_PUBLIC_SUPABASE_ANON_KEY= # Supabase anonymous/public key
68+
SUPABASE_SERVICE_ROLE_KEY= # Supabase service role key (server-only, bypasses RLS)

.eslintrc

Lines changed: 0 additions & 4 deletions
This file was deleted.

.github/workflows/ci.yml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [dev]
6+
pull_request:
7+
branches: [dev]
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
env:
14+
NODE_VERSION: "20"
15+
16+
jobs:
17+
ci:
18+
name: Lint, Build & Test
19+
runs-on: ubuntu-latest
20+
timeout-minutes: 15
21+
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v4
25+
26+
- name: Setup pnpm
27+
uses: pnpm/action-setup@v4
28+
29+
- name: Setup Node.js
30+
uses: actions/setup-node@v4
31+
with:
32+
node-version: ${{ env.NODE_VERSION }}
33+
cache: pnpm
34+
35+
- name: Install dependencies
36+
run: pnpm install --frozen-lockfile
37+
38+
- name: Type-check
39+
run: pnpm exec tsc --noEmit
40+
41+
- name: Lint (Biome)
42+
run: pnpm exec biome check .
43+
44+
- name: Build
45+
run: pnpm build
46+
env:
47+
# Provide dummy values for build-time env vars so Next.js build succeeds
48+
NEXT_PUBLIC_SANITY_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_SANITY_PROJECT_ID }}
49+
NEXT_PUBLIC_SANITY_DATASET: ${{ secrets.NEXT_PUBLIC_SANITY_DATASET }}
50+
NEXT_PUBLIC_SANITY_API_VERSION: ${{ secrets.NEXT_PUBLIC_SANITY_API_VERSION }}
51+
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
52+
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
53+
SANITY_API_READ_TOKEN: ${{ secrets.SANITY_API_READ_TOKEN }}
54+
55+
- name: Cache Playwright browsers
56+
uses: actions/cache@v4
57+
id: playwright-cache
58+
with:
59+
path: ~/.cache/ms-playwright
60+
key: playwright-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
61+
62+
- name: Install Playwright browsers
63+
if: steps.playwright-cache.outputs.cache-hit != 'true'
64+
run: pnpm exec playwright install --with-deps chromium
65+
66+
- name: Install Playwright system deps
67+
if: steps.playwright-cache.outputs.cache-hit == 'true'
68+
run: pnpm exec playwright install-deps chromium
69+
70+
- name: Run Playwright tests
71+
run: pnpm exec playwright test
72+
env:
73+
CI: true
74+
PLAYWRIGHT_BASE_URL: http://localhost:3000
75+
NEXT_PUBLIC_SANITY_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_SANITY_PROJECT_ID }}
76+
NEXT_PUBLIC_SANITY_DATASET: ${{ secrets.NEXT_PUBLIC_SANITY_DATASET }}
77+
NEXT_PUBLIC_SANITY_API_VERSION: ${{ secrets.NEXT_PUBLIC_SANITY_API_VERSION }}
78+
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
79+
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
80+
81+
- name: Upload Playwright report
82+
uses: actions/upload-artifact@v4
83+
if: ${{ !cancelled() }}
84+
with:
85+
name: playwright-report
86+
path: playwright-report/
87+
retention-days: 7

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99

1010
# testing
1111
/coverage
12+
/test-results/
13+
/playwright-report/
14+
/blob-report/
15+
/playwright/.cache/
1216

1317
# next.js
1418
/.next/
@@ -46,4 +50,4 @@ next-env.d.ts
4650
.genkit/
4751
# Firebase debug files
4852
firebase-debug.log
49-
firebase-debug.*.log
53+
firebase-debug.*.logpackage-lock.json
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"use server";
2+
3+
import { redirect } from "next/navigation";
4+
import { createClient } from "@/lib/supabase/server";
5+
6+
export async function signOut() {
7+
const supabase = await createClient();
8+
await supabase.auth.signOut();
9+
redirect("/dashboard/login");
10+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { createClient } from "@/lib/supabase/server";
2+
import { NextResponse } from "next/server";
3+
4+
export async function GET(request: Request) {
5+
const { searchParams, origin } = new URL(request.url);
6+
const code = searchParams.get("code");
7+
const next = searchParams.get("next") ?? "/dashboard";
8+
9+
if (code) {
10+
const supabase = await createClient();
11+
const { error } = await supabase.auth.exchangeCodeForSession(code);
12+
if (!error) {
13+
return NextResponse.redirect(`${origin}${next}`);
14+
}
15+
}
16+
17+
return NextResponse.redirect(
18+
`${origin}/dashboard/login?error=Could+not+authenticate`,
19+
);
20+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"use server";
2+
3+
import { revalidatePath } from "next/cache";
4+
import { dashboardClient } from "@/lib/sanity/dashboard";
5+
6+
export async function approveIdea(id: string) {
7+
await dashboardClient.patch(id).set({ status: "approved" }).commit();
8+
revalidatePath("/dashboard/content");
9+
}
10+
11+
export async function rejectIdea(id: string) {
12+
await dashboardClient.patch(id).set({ status: "rejected" }).commit();
13+
revalidatePath("/dashboard/content");
14+
}

0 commit comments

Comments
 (0)