Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/postgres

# `npx auth secret` or `openssl rand -hex 32`
# `openssl rand -hex 32`
NEXTAUTH_SECRET=****

AUTH_PROVIDER_URL=https://auth.f3nation.com
Expand Down
110 changes: 110 additions & 0 deletions .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: Pull Request Quality Gates

on:
pull_request:

env:
DATABASE_URL: postgres://postgres:postgres@127.0.0.1:5432/postgres
NEXTAUTH_SECRET: "****"
AUTH_PROVIDER_URL: https://auth.f3nation.com
NEXTAUTH_URL: https://localhost:3001
NEXT_PUBLIC_NEXTAUTH_URL: https://localhost:3001
OAUTH_REDIRECT_URI: https://localhost:3001/callback
OAUTH_CLIENT_ID: local-client
OAUTH_CLIENT_SECRET: "****"

jobs:
format-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json

- name: Install dependencies
run: npm ci

- name: Format check
run: npm run format:check

lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json

- name: Install dependencies
run: npm ci

- name: Lint
run: npm run lint

typecheck:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json

- name: Install dependencies
run: npm ci

- name: Type check
run: npm run typecheck

build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm run test
7 changes: 7 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
.next
out
dist
build
coverage
pglite-debug.log
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ The Exicon and Lexicon pages support URL query parameters for filtering and sear

The Exicon (`/exicon`) supports the following query parameters:

| Parameter | Type | Description | Default |
|-----------|------|-------------|---------|
| `search` | string | Search exercises by name or alias | - |
| `letter` | string | Filter by first letter (A-Z) | `All` |
| `tags` | string | Comma-separated tag names | - |
| `tagLogic` | string | Tag combination logic: `AND` or `OR` | `OR` |
| Parameter | Type | Description | Default |
| ---------- | ------ | ------------------------------------ | ------- |
| `search` | string | Search exercises by name or alias | - |
| `letter` | string | Filter by first letter (A-Z) | `All` |
| `tags` | string | Comma-separated tag names | - |
| `tagLogic` | string | Tag combination logic: `AND` or `OR` | `OR` |

**Examples:**

Expand All @@ -50,10 +50,10 @@ The Exicon (`/exicon`) supports the following query parameters:

The Lexicon (`/lexicon`) supports the following query parameters:

| Parameter | Type | Description | Default |
|-----------|------|-------------|---------|
| `search` | string | Search terms by name, alias, or description | - |
| `letter` | string | Filter by first letter (A-Z) | `All` |
| Parameter | Type | Description | Default |
| --------- | ------ | ------------------------------------------- | ------- |
| `search` | string | Search terms by name, alias, or description | - |
| `letter` | string | Filter by first letter (A-Z) | `All` |

**Examples:**

Expand Down
2 changes: 1 addition & 1 deletion components.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
}
2 changes: 1 addition & 1 deletion docs/blueprint.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
- Accent: A bright blue (#007BFF) for interactive elements and links.
- Clean and modern sans-serif fonts for readability and accessibility.
- Use consistent and recognizable icons for navigation and actions.
- Responsive layout that adapts to different screen sizes.
- Responsive layout that adapts to different screen sizes.
2 changes: 1 addition & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import nextConfig from 'eslint-config-next';
import nextConfig from "eslint-config-next";

export default nextConfig;
32 changes: 19 additions & 13 deletions middleware.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
import { NextRequest, NextResponse } from 'next/server';
import { NextRequest, NextResponse } from "next/server";

export function middleware(request: NextRequest) {
// Handle CORS for callback routes
if (
request.nextUrl.pathname.startsWith('/callback') ||
request.nextUrl.pathname.startsWith('/api/callback')
request.nextUrl.pathname.startsWith("/callback") ||
request.nextUrl.pathname.startsWith("/api/callback")
) {
// Handle preflight requests
if (request.method === 'OPTIONS') {
if (request.method === "OPTIONS") {
return new NextResponse(null, {
status: 200,
headers: {
'Access-Control-Allow-Origin': 'https://auth.f3nation.com',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400',
"Access-Control-Allow-Origin": "https://auth.f3nation.com",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
"Access-Control-Max-Age": "86400",
},
});
}

// Add CORS headers to all callback responses
const response = NextResponse.next();

response.headers.set('Access-Control-Allow-Origin', 'https://auth.f3nation.com');
response.headers.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');

response.headers.set(
"Access-Control-Allow-Origin",
"https://auth.f3nation.com",
);
response.headers.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
response.headers.set(
"Access-Control-Allow-Headers",
"Content-Type, Authorization",
);

return response;
}
Expand All @@ -33,5 +39,5 @@ export function middleware(request: NextRequest) {
}

export const config = {
matcher: ['/callback/:path*', '/api/callback/:path*'],
matcher: ["/callback/:path*", "/api/callback/:path*"],
};
72 changes: 41 additions & 31 deletions migrations/1747064544503_create-tags-table.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,50 @@ exports.shorthands = undefined;
* @returns {Promise<void> | void}
*/
exports.up = (pgm) => {
console.log('[MIGRATION_LOG] Starting migration: 1747064544503_create-tags-table.js UP');
pgm.createTable('tags', {
id: { type: 'text', primaryKey: true },
name: { type: 'text', notNull: true, unique: true },
console.log(
"[MIGRATION_LOG] Starting migration: 1747064544503_create-tags-table.js UP",
);
pgm.createTable("tags", {
id: { type: "text", primaryKey: true },
name: { type: "text", notNull: true, unique: true },
created_at: {
type: 'timestamp',
type: "timestamp",
notNull: true,
default: pgm.func('current_timestamp'),
default: pgm.func("current_timestamp"),
},
});

const initialTags = [
{ id: 't1', name: 'Arms' },
{ id: 't2', name: 'Legs' },
{ id: 't3', name: 'Core' },
{ id: 't4', name: 'Cardio' },
{ id: 't5', name: 'Full Body' },
{ id: 't6', name: 'Partner' },
{ id: 't7', name: 'Coupon' },
{ id: 't8', name: 'Music' },
{ id: 't9', name: 'Mosey' },
{ id: 't10', name: 'Static' },
{ id: 't11', name: 'Strength' },
{ id: 't12', name: 'AMRAP' },
{ id: 't13', name: 'EMOM' },
{ id: 't14', name: 'Reps' },
{ id: 't15', name: 'Timed' },
{ id: 't16', name: 'Distance' },
{ id: 't17', name: 'Routine' },
{ id: 't18', name: 'Run' },
{ id: 't19', name: 'Warm-Up' },
{ id: 't20', name: 'Mary' },
{ id: "t1", name: "Arms" },
{ id: "t2", name: "Legs" },
{ id: "t3", name: "Core" },
{ id: "t4", name: "Cardio" },
{ id: "t5", name: "Full Body" },
{ id: "t6", name: "Partner" },
{ id: "t7", name: "Coupon" },
{ id: "t8", name: "Music" },
{ id: "t9", name: "Mosey" },
{ id: "t10", name: "Static" },
{ id: "t11", name: "Strength" },
{ id: "t12", name: "AMRAP" },
{ id: "t13", name: "EMOM" },
{ id: "t14", name: "Reps" },
{ id: "t15", name: "Timed" },
{ id: "t16", name: "Distance" },
{ id: "t17", name: "Routine" },
{ id: "t18", name: "Run" },
{ id: "t19", name: "Warm-Up" },
{ id: "t20", name: "Mary" },
];

for (const tag of initialTags) {
pgm.sql(`INSERT INTO tags (id, name) VALUES ('${tag.id}', '${tag.name.replace(/'/g, "''")}');`);
pgm.sql(
`INSERT INTO tags (id, name) VALUES ('${tag.id}', '${tag.name.replace(/'/g, "''")}');`,
);
}
console.log('[MIGRATION_LOG] Finished migration: 1747064544503_create-tags-table.js UP');
console.log(
"[MIGRATION_LOG] Finished migration: 1747064544503_create-tags-table.js UP",
);
};

/**
Expand All @@ -55,7 +61,11 @@ exports.up = (pgm) => {
* @returns {Promise<void> | void}
*/
exports.down = (pgm) => {
console.log('[MIGRATION_LOG] Starting migration: 1747064544503_create-tags-table.js DOWN');
pgm.dropTable('tags');
console.log('[MIGRATION_LOG] Finished migration: 1747064544503_create-tags-table.js DOWN');
console.log(
"[MIGRATION_LOG] Starting migration: 1747064544503_create-tags-table.js DOWN",
);
pgm.dropTable("tags");
console.log(
"[MIGRATION_LOG] Finished migration: 1747064544503_create-tags-table.js DOWN",
);
};
10 changes: 5 additions & 5 deletions migrations/1747064552223_create-user-submissions-table.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ exports.shorthands = undefined;
*/
exports.up = (pgm) => {
console.log(
"[MIGRATION_LOG] Starting migration: create-user-submissions-table UP"
"[MIGRATION_LOG] Starting migration: create-user-submissions-table UP",
);

pgm.createTable("user_submissions", {
Expand Down Expand Up @@ -59,7 +59,7 @@ exports.up = (pgm) => {
`);

console.log(
"[MIGRATION_LOG] Finished migration: create-user-submissions-table UP"
"[MIGRATION_LOG] Finished migration: create-user-submissions-table UP",
);
};

Expand All @@ -69,17 +69,17 @@ exports.up = (pgm) => {
*/
exports.down = (pgm) => {
console.log(
"[MIGRATION_LOG] Starting migration: create-user-submissions-table DOWN"
"[MIGRATION_LOG] Starting migration: create-user-submissions-table DOWN",
);

pgm.sql(
`DROP TRIGGER IF EXISTS trigger_user_submissions_updated_at ON user_submissions;`
`DROP TRIGGER IF EXISTS trigger_user_submissions_updated_at ON user_submissions;`,
);
pgm.sql(`DROP FUNCTION IF EXISTS update_updated_at_column;`);

pgm.dropTable("user_submissions");

console.log(
"[MIGRATION_LOG] Finished migration: create-user-submissions-table DOWN"
"[MIGRATION_LOG] Finished migration: create-user-submissions-table DOWN",
);
};
Loading