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
22 changes: 22 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Repo Checks

on:
pull_request:
branches:
- main
workflow_dispatch:

jobs:
checks:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: frontend/package-lock.json

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CI workflow runs npm run gitcheck which executes the setup script with --skip-supabase --skip-env --no-start flags, followed by linting and testing. However, the setup script will still run npm install in the frontend directory at line 131. Since the workflow already has Node.js set up with caching, consider adding an explicit npm ci step in the workflow before running checks to ensure dependencies are installed, or document that the gitcheck script handles this.

Suggested change
cache-dependency-path: frontend/package-lock.json
cache-dependency-path: frontend/package-lock.json
- name: Install dependencies
run: npm ci
working-directory: frontend

Copilot uses AI. Check for mistakes.
- name: Run checks
run: npm run gitcheck
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
.next
out
node_modules
coverage
.vercel

# OS/Editor cruft
.DS_Store
Expand Down
6 changes: 6 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
.next
out
.supabase
coverage
**/package-lock.json
5 changes: 5 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"printWidth": 100,
"singleQuote": false,

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Prettier configuration sets "singleQuote": false, which means double quotes will be used. However, the existing codebase may have a mix of quote styles. Consider running Prettier on the entire codebase to ensure consistency, or verify that this configuration matches the project's existing style preferences.

Copilot uses AI. Check for mistakes.
"semi": true
}
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,62 @@ Students struggle to find consolidated, high‑quality, course‑specific study
- [Wieland Rodriguez](https://www.linkedin.com/in/wieland-rodriguez) - Developer
- [Emma Walker](https://www.linkedin.com/) - Developer

## Getting Started

The fastest way to get up and running is the setup script. It checks your local
dependencies, verifies environment variables, installs packages, and then starts
the dev server only when everything looks good.

```bash
npm run setup
```

### What the setup script checks
- Node.js is installed and prints the version.
- Supabase CLI is installed (or it will tell you how to install it).
- Required environment variables exist in `frontend/.env.local`.
- Frontend dependencies are installed.

### Supabase CLI install (Windows)
Run this in PowerShell:

```powershell
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
iwr -useb get.scoop.sh | iex
scoop install supabase
```

### Supabase CLI install (macOS)

```bash
brew install supabase/tap/supabase
```

### Required environment variables
Create `frontend/.env.local` and include:
- `NEXT_PUBLIC_SUPABASE_URL`
- `NEXT_PUBLIC_SUPABASE_ANON_KEY`
- `SUPABASE_SERVICE_ROLE_KEY`

### Start the dev server
If you want to skip the full checks and just start after installing updates:

```bash
npm run start
```

### Auth flow
Open `/auth`, enter your `@calpoly.edu` email, and use the one-time code to log in.
After that, you will be routed to onboarding or the dashboard.

## Documentation

- Product requirements: `docs/PRD.md`
- Tech stack: `docs/Note_Sharer_Tech_Stack.md`
- Project charter: `docs/project-charter.md`
- Contributing: `docs/contributing.md`
- PR review guide: `docs/PR_REVIEW_GUIDE.md`

## Contributing

Visit [contributing.md](docs/contributing.md) on info for how to contribute to this repo.

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grammar error: "on info for" should be "for info on" or "for information on".

Suggested change
Visit [contributing.md](docs/contributing.md) on info for how to contribute to this repo.
Visit [contributing.md](docs/contributing.md) for info on how to contribute to this repo.

Copilot uses AI. Check for mistakes.
Comment on lines +76 to 81

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation references "docs/contributing.md" and "docs/PR_REVIEW_GUIDE.md" but these files are not included in this PR. Ensure these files exist in the repository or will be added in a follow-up PR to avoid broken documentation links.

Suggested change
- Contributing: `docs/contributing.md`
- PR review guide: `docs/PR_REVIEW_GUIDE.md`
## Contributing
Visit [contributing.md](docs/contributing.md) on info for how to contribute to this repo.
- Contributing guidelines: (to be added in `docs/contributing.md`)
- PR review guide: (to be added in `docs/PR_REVIEW_GUIDE.md`)
## Contributing
Contributions are welcome. Please open an issue or pull request with your proposed changes; formal contributing guidelines will be added to `docs/contributing.md` in a future update.

Copilot uses AI. Check for mistakes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
13 changes: 13 additions & 0 deletions frontend/__tests__/nicknames.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { generateRandomNickname, generateRandomNicknames } from "@/lib/nicknames";

describe("nicknames", () => {
it("generates a nickname with letters and digits", () => {
const nickname = generateRandomNickname();
expect(nickname).toMatch(/^[A-Za-z]+[A-Za-z]+[0-9]{1,2}$/);

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern /^[A-Za-z]+[A-Za-z]+[0-9]{1,2}$/ expects at least two letter groups followed by digits, but it would be clearer to express this as /^[A-Za-z]{2,}[0-9]{1,2}$/ if the intent is to match 2 or more letters followed by 1-2 digits. The current pattern /^[A-Za-z]+[A-Za-z]+[0-9]{1,2}$/ is redundant with two consecutive [A-Za-z]+ groups.

Suggested change
expect(nickname).toMatch(/^[A-Za-z]+[A-Za-z]+[0-9]{1,2}$/);
expect(nickname).toMatch(/^[A-Za-z]{2,}[0-9]{1,2}$/);

Copilot uses AI. Check for mistakes.
});

it("generates the requested count", () => {
const nicknames = generateRandomNicknames(3);
expect(nicknames).toHaveLength(3);
});
});
1 change: 1 addition & 0 deletions frontend/app/api/course-submissions/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export async function POST(request: Request) {
let payload: SubmissionPayload;
try {
payload = (await request.json()) as SubmissionPayload;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
return NextResponse.json(
{ error: "Invalid request payload." },
Expand Down
1 change: 0 additions & 1 deletion frontend/app/auth/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export default function AuthPage() {
const checkSession = async () => {
const { data, error } = await supabase.auth.getSession();
if (error) {
// eslint-disable-next-line no-console
console.error("Failed to fetch session", error);
}
if (data?.session) {
Expand Down
5 changes: 5 additions & 0 deletions frontend/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export default function DashboardPage() {
const [noteSearch, setNoteSearch] = useState("");
const [accessToken, setAccessToken] = useState<string | null>(null);
const [tokenLoaded, setTokenLoaded] = useState(false);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [isUploadOpen, setIsUploadOpen] = useState(false);

const [isCourseRequestOpen, setIsCourseRequestOpen] = useState(false);
Expand Down Expand Up @@ -114,6 +115,7 @@ export default function DashboardPage() {
}
const data = await res.json();
setClasses(data.classes || []);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (err) {
setClassesError("Failed to load classes");
setClasses([]);
Expand Down Expand Up @@ -150,6 +152,7 @@ export default function DashboardPage() {
setFreeDownloads(
Number.isFinite(data?.freeDownloads) ? Number(data.freeDownloads) : 0,
);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
setCredits(null);
setFreeDownloads(null);
Expand Down Expand Up @@ -218,6 +221,7 @@ export default function DashboardPage() {
}

setHasMore(Boolean(data.hasMore));
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (err) {
setNotesError("Unexpected error fetching notes");
setHasMore(false);
Expand Down Expand Up @@ -328,6 +332,7 @@ export default function DashboardPage() {
setCourseRequestStatus("success");
setCourseRequestMessage("Request submitted. We will review it soon.");
setCourseRequest(emptyCourseRequest);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
setCourseRequestStatus("error");
setCourseRequestMessage("Failed to submit the request. Try again.");
Expand Down
2 changes: 0 additions & 2 deletions frontend/app/onboarding/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ export default function OnboardingPage() {
const nickname = await generateUniqueNickname(supabase);
setDisplayName(nickname);
} catch (generationError) {
// eslint-disable-next-line no-console
console.error("Failed to generate nickname", generationError);
setError("Unable to generate a nickname. Please try again.");
} finally {
Expand All @@ -77,7 +76,6 @@ export default function OnboardingPage() {
nameToSave = await generateUniqueNickname(supabase);
setDisplayName(nameToSave);
} catch (generationError) {
// eslint-disable-next-line no-console
console.error("Failed to generate nickname", generationError);
setError("Unable to generate a nickname. Please try again.");
setSaving(false);
Expand Down
2 changes: 2 additions & 0 deletions frontend/app/test-upload/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// app/test-upload/page.tsx
"use client";

// eslint-disable-next-line @typescript-eslint/no-unused-vars
import type { Session } from "@supabase/supabase-js";
import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
import { supabase } from "@/lib/supabaseClient";

export default function TestUploadPage() {
const router = useRouter();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [ isAuthenticated, setIsAuthenticated] = useState(false);

const [file, setFile] = useState<File | null>(null);
Expand Down
3 changes: 3 additions & 0 deletions frontend/app/upload/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ export default function UploadPage() {
setCourseRequestStatus("success");
setCourseRequestMessage("Request submitted. We will review it soon.");
setCourseRequest(emptyCourseRequest);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
setCourseRequestStatus("error");
setCourseRequestMessage("Failed to submit the request. Try again.");
Expand Down Expand Up @@ -240,6 +241,7 @@ export default function UploadPage() {
}
const data = await res.json();
setClasses(data.classes || []);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (err) {
setClassesError("Failed to load classes");
setClasses([]);
Expand Down Expand Up @@ -333,6 +335,7 @@ export default function UploadPage() {

setResult(`${res.status}: ${JSON.stringify(payload)}`);
setIsSuccess(true);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
setSubmitError("Upload failed. Please check your connection and retry.");
} finally {
Expand Down
6 changes: 6 additions & 0 deletions frontend/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import nextTs from "eslint-config-next/typescript";
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
{
files: ["**/*.cjs"],
rules: {
"@typescript-eslint/no-require-imports": "off",
},
},
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
Expand Down
13 changes: 13 additions & 0 deletions frontend/jest.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const nextJest = require("next/jest");

const createJestConfig = nextJest({ dir: "./" });

const customJestConfig = {
testEnvironment: "node",
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/$1",
},
testPathIgnorePatterns: ["<rootDir>/.next/", "<rootDir>/node_modules/"],

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Jest configuration uses CommonJS format (.cjs) but the test file uses ES modules syntax (import). Jest 29 requires additional configuration to handle ES modules. Consider adding "testEnvironment": "node" is correct, but you may need to add "transform": {} and "extensionsToTreatAsEsm": [".ts"] or use a transformer like ts-jest to properly handle TypeScript with ES modules in Jest.

Suggested change
testPathIgnorePatterns: ["<rootDir>/.next/", "<rootDir>/node_modules/"],
testPathIgnorePatterns: ["<rootDir>/.next/", "<rootDir>/node_modules/"],
extensionsToTreatAsEsm: [".ts", ".tsx"],

Copilot uses AI. Check for mistakes.
};

module.exports = createJestConfig(customJestConfig);
1 change: 0 additions & 1 deletion frontend/lib/nicknames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ export async function generateUniqueNickname(
}

// If not unique, try again (this is rare but possible)
// eslint-disable-next-line no-console
console.log(`Nickname collision: ${nickname}, retrying... (attempt ${attempt + 1}/${maxAttempts})`);
}

Expand Down
Loading
Loading